summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@qt.io>2018-10-22 09:53:54 +0200
committerEike Ziller <eike.ziller@qt.io>2018-10-22 09:53:54 +0200
commit95db30bd3a5808890c03864a1da84d443cc8bf38 (patch)
tree92415e861f4818a28fdc2b4526bddfe1e3df46a6 /src
parent16de556c8699766e661de00cba0fc8de58109517 (diff)
parent1cad74a7d426c0eeac53cd838cdc89c9788f84aa (diff)
downloadqt-creator-95db30bd3a5808890c03864a1da84d443cc8bf38.tar.gz
Merge remote-tracking branch 'origin/4.8'
Conflicts: src/plugins/debugger/debuggeritem.cpp tests/unit/unittest/unittest.pro Change-Id: Id2e4e9c2bc87b2556d7c2845aea3fe2fa11b630b
Diffstat (limited to 'src')
-rw-r--r--src/libs/languageserverprotocol/basemessage.cpp10
-rw-r--r--src/libs/languageserverprotocol/jsonobject.cpp2
-rw-r--r--src/libs/languageserverprotocol/jsonrpcmessages.cpp4
-rw-r--r--src/libs/languageserverprotocol/jsonrpcmessages.h4
-rw-r--r--src/libs/languageserverprotocol/languagefeatures.cpp4
-rw-r--r--src/libs/languageserverprotocol/lsptypes.cpp2
-rw-r--r--src/libs/utils/textutils.cpp15
-rw-r--r--src/libs/utils/textutils.h42
-rw-r--r--src/plugins/android/androidtoolchain.cpp5
-rw-r--r--src/plugins/autotest/autotestplugin.cpp32
-rw-r--r--src/plugins/clangcodemodel/clangassistproposalitem.cpp8
-rw-r--r--src/plugins/clangcodemodel/clangbackendcommunicator.cpp28
-rw-r--r--src/plugins/clangcodemodel/clangbackendcommunicator.h3
-rw-r--r--src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp12
-rw-r--r--src/plugins/clangcodemodel/clangmodelmanagersupport.cpp23
-rw-r--r--src/plugins/clangcodemodel/clangmodelmanagersupport.h3
-rw-r--r--src/plugins/clangcodemodel/clangutils.h50
-rw-r--r--src/plugins/clangformat/clangformat.pro3
-rw-r--r--src/plugins/clangformat/clangformat.qbs3
-rw-r--r--src/plugins/clangformat/clangformatconfigwidget.cpp93
-rw-r--r--src/plugins/clangformat/clangformatconfigwidget.h5
-rw-r--r--src/plugins/clangformat/clangformatconfigwidget.ui13
-rw-r--r--src/plugins/clangformat/clangformatindenter.cpp500
-rw-r--r--src/plugins/clangformat/clangformatindenter.h8
-rw-r--r--src/plugins/clangformat/clangformatplugin.cpp8
-rw-r--r--src/plugins/clangformat/clangformatplugin.h2
-rw-r--r--src/plugins/clangformat/clangformatutils.h51
-rw-r--r--src/plugins/cppcheck/cppcheckoptions.cpp2
-rw-r--r--src/plugins/cpptools/cppmodelmanager.cpp5
-rw-r--r--src/plugins/cpptools/cppmodelmanager.h2
-rw-r--r--src/plugins/cpptools/cppmodelmanagersupport.h1
-rw-r--r--src/plugins/cpptools/cppmodelmanagersupportinternal.h1
-rw-r--r--src/plugins/cpptools/cpptools_clangtidychecks.h159
-rw-r--r--src/plugins/debugger/breakhandler.cpp21
-rw-r--r--src/plugins/debugger/breakhandler.h2
-rw-r--r--src/plugins/debugger/cdb/cdbengine.cpp38
-rw-r--r--src/plugins/debugger/cdb/cdbengine.h12
-rw-r--r--src/plugins/debugger/debuggerconstants.h3
-rw-r--r--src/plugins/debugger/debuggerengine.cpp52
-rw-r--r--src/plugins/debugger/debuggerengine.h10
-rw-r--r--src/plugins/debugger/debuggeritem.cpp8
-rw-r--r--src/plugins/debugger/debuggeritem.h4
-rw-r--r--src/plugins/debugger/debuggerplugin.cpp89
-rw-r--r--src/plugins/debugger/debuggerruncontrol.cpp5
-rw-r--r--src/plugins/debugger/debuggerruncontrol.h2
-rw-r--r--src/plugins/debugger/disassembleragent.cpp1
-rw-r--r--src/plugins/debugger/enginemanager.cpp5
-rw-r--r--src/plugins/debugger/gdb/gdbengine.cpp71
-rw-r--r--src/plugins/debugger/gdb/gdbengine.h6
-rw-r--r--src/plugins/debugger/lldb/lldbengine.cpp20
-rw-r--r--src/plugins/debugger/lldb/lldbengine.h6
-rw-r--r--src/plugins/debugger/pdb/pdbengine.cpp48
-rw-r--r--src/plugins/debugger/pdb/pdbengine.h7
-rw-r--r--src/plugins/debugger/qml/qmlengine.cpp17
-rw-r--r--src/plugins/debugger/qml/qmlengine.h6
-rw-r--r--src/plugins/git/TODO.txt17
-rw-r--r--src/plugins/git/branchmodel.cpp2
-rw-r--r--src/plugins/git/branchview.cpp44
-rw-r--r--src/plugins/git/branchview.h2
-rw-r--r--src/plugins/help/helpplugin.cpp2
-rw-r--r--src/plugins/languageclient/baseclient.cpp38
-rw-r--r--src/plugins/languageclient/baseclient.h9
-rw-r--r--src/plugins/languageclient/languageclientcodeassist.cpp73
-rw-r--r--src/plugins/languageclient/languageclientsettings.cpp430
-rw-r--r--src/plugins/languageclient/languageclientsettings.h63
-rw-r--r--src/plugins/projectexplorer/customexecutablerunconfiguration.cpp5
-rw-r--r--src/plugins/projectexplorer/customexecutablerunconfiguration.h1
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.cpp2
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp3
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.cpp5
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.h2
-rw-r--r--src/plugins/projectexplorer/projectexplorer.cpp1
-rw-r--r--src/plugins/projectexplorer/projectwelcomepage.cpp10
-rw-r--r--src/plugins/projectexplorer/projectwizardpage.cpp5
-rw-r--r--src/plugins/projectexplorer/runconfiguration.cpp18
-rw-r--r--src/plugins/projectexplorer/runconfiguration.h3
-rw-r--r--src/plugins/projectexplorer/toolchainmanager.cpp8
-rw-r--r--src/plugins/projectexplorer/toolchainmanager.h2
-rw-r--r--src/plugins/projectexplorer/windebuginterface.cpp2
-rw-r--r--src/plugins/qbsprojectmanager/qbsproject.cpp14
-rw-r--r--src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp13
-rw-r--r--src/plugins/qmldesigner/designercore/instances/puppetcreator.h2
-rw-r--r--src/plugins/qmldesigner/settingspage.cpp15
-rw-r--r--src/plugins/qmlprofiler/tests/qmlprofilertool_test.cpp10
-rw-r--r--src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp7
-rw-r--r--src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.h1
-rw-r--r--src/plugins/texteditor/codeassist/codeassistant.cpp15
-rw-r--r--src/plugins/texteditor/codeassist/iassistprocessor.h1
-rw-r--r--src/plugins/texteditor/texteditor.cpp2
-rw-r--r--src/plugins/vcsbase/vcscommand.cpp11
m---------src/shared/qbs0
-rw-r--r--src/tools/clangbackend/source/clangfollowsymbol.cpp2
-rw-r--r--src/tools/clangbackend/source/clangtranslationunit.cpp12
-rw-r--r--src/tools/clangbackend/source/codecompleter.cpp8
-rw-r--r--src/tools/clangbackend/source/codecompletionsextractor.cpp30
-rw-r--r--src/tools/clangbackend/source/codecompletionsextractor.h6
-rw-r--r--src/tools/clangbackend/source/skippedsourceranges.cpp6
-rw-r--r--src/tools/clangbackend/source/sourcelocation.cpp79
-rw-r--r--src/tools/clangbackend/source/sourcelocation.h26
-rw-r--r--src/tools/clangbackend/source/sourcerange.cpp2
-rw-r--r--src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri4
-rw-r--r--src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h6
-rw-r--r--src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h6
-rw-r--r--src/tools/clangpchmanagerbackend/source/usedmacroandsourcestorage.h198
-rw-r--r--src/tools/clangpchmanagerbackend/source/usedmacroandsourcestorageinterface.h52
-rw-r--r--src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri1
-rw-r--r--src/tools/clangrefactoringbackend/source/collectmacrospreprocessorcallbacks.h6
-rw-r--r--src/tools/clangrefactoringbackend/source/indexdataconsumer.cpp10
-rw-r--r--src/tools/clangrefactoringbackend/source/indexdataconsumer.h4
-rw-r--r--src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h237
-rw-r--r--src/tools/clangrefactoringbackend/source/symbolindexer.cpp16
-rw-r--r--src/tools/clangrefactoringbackend/source/symbolindexer.h3
-rw-r--r--src/tools/clangrefactoringbackend/source/symbolindexing.h17
-rw-r--r--src/tools/clangrefactoringbackend/source/symbolstorage.h216
-rw-r--r--src/tools/clangrefactoringbackend/source/symbolstorageinterface.h4
115 files changed, 1981 insertions, 1344 deletions
diff --git a/src/libs/languageserverprotocol/basemessage.cpp b/src/libs/languageserverprotocol/basemessage.cpp
index 70204a139c..65fc12e449 100644
--- a/src/libs/languageserverprotocol/basemessage.cpp
+++ b/src/libs/languageserverprotocol/basemessage.cpp
@@ -77,7 +77,7 @@ static QPair<QByteArray, QByteArray> splitHeaderFieldLine(
return {headerFieldLine.mid(0, assignmentIndex),
headerFieldLine.mid(assignmentIndex + fieldSeparatorLength)};
}
- parseError = BaseMessage::tr("Unexpected header line \"%1\"")
+ parseError = BaseMessage::tr("Unexpected header line \"%1\".")
.arg(QLatin1String(headerFieldLine));
return {};
}
@@ -97,8 +97,8 @@ static void parseContentType(BaseMessage &message, QByteArray contentType, QStri
if (equalindex > 0)
codec = QTextCodec::codecForName(charset);
if (!codec) {
- parseError = BaseMessage::tr("Cannot decode content with \"%1\" "
- "falling back to \"%2\"")
+ parseError = BaseMessage::tr("Cannot decode content with \"%1\". "
+ "Falling back to \"%2\".")
.arg(QLatin1String(charset),
QLatin1String(defaultCharset));
}
@@ -113,7 +113,7 @@ static void parseContentLength(BaseMessage &message, QByteArray contentLength, Q
bool ok = true;
message.contentLength = QString::fromLatin1(contentLength).toInt(&ok);
if (!ok) {
- parseError = BaseMessage::tr("Expected an integer in \"%1\", but got \"%2\"")
+ parseError = BaseMessage::tr("Expected an integer in \"%1\", but got \"%2\".")
.arg(contentLengthFieldName, QLatin1String(contentLength));
}
}
@@ -146,7 +146,7 @@ void BaseMessage::parse(QBuffer *data, QString &parseError, BaseMessage &message
} else if (headerFieldName == contentTypeFieldName) {
parseContentType(message, headerFieldValue, parseError);
} else {
- parseError = tr("Unexpected header field \"%1\" in \"%2\"")
+ parseError = tr("Unexpected header field \"%1\" in \"%2\".")
.arg(QLatin1String(headerFieldName),
QLatin1String(headerFieldLine));
}
diff --git a/src/libs/languageserverprotocol/jsonobject.cpp b/src/libs/languageserverprotocol/jsonobject.cpp
index ea61092ec3..1f471db47b 100644
--- a/src/libs/languageserverprotocol/jsonobject.cpp
+++ b/src/libs/languageserverprotocol/jsonobject.cpp
@@ -104,7 +104,7 @@ QString JsonObject::valueTypeString(QJsonValue::Type type)
QString JsonObject::errorString(QJsonValue::Type expected, QJsonValue::Type actual)
{
- return tr("Expected Type %1 but value contained %2")
+ return tr("Expected type %1 but value contained %2")
.arg(valueTypeString(expected), valueTypeString(actual));
}
diff --git a/src/libs/languageserverprotocol/jsonrpcmessages.cpp b/src/libs/languageserverprotocol/jsonrpcmessages.cpp
index 85d1813585..15f19b4c9a 100644
--- a/src/libs/languageserverprotocol/jsonrpcmessages.cpp
+++ b/src/libs/languageserverprotocol/jsonrpcmessages.cpp
@@ -141,9 +141,9 @@ QJsonObject JsonRpcMessageHandler::toJsonObject(const QByteArray &_content,
if (doc.isObject())
return doc.object();
if (doc.isNull())
- parseError = tr("Could not parse Json message '%1'").arg(error.errorString());
+ parseError = tr("Could not parse JSON message \"%1\".").arg(error.errorString());
else
- parseError = tr("Expected Json object, but got a json '%1'").arg(docTypeName(doc));
+ parseError = tr("Expected a JSON object, but got a JSON \"%1\".").arg(docTypeName(doc));
return QJsonObject();
}
diff --git a/src/libs/languageserverprotocol/jsonrpcmessages.h b/src/libs/languageserverprotocol/jsonrpcmessages.h
index 7a3fea1158..3225fd4866 100644
--- a/src/libs/languageserverprotocol/jsonrpcmessages.h
+++ b/src/libs/languageserverprotocol/jsonrpcmessages.h
@@ -125,7 +125,7 @@ public:
}
if (errorMessage)
*errorMessage = QCoreApplication::translate("LanguageServerProtocol::Notification",
- "No parameters in '%1'").arg(method());
+ "No parameters in \"%1\".").arg(method());
return false;
}
};
@@ -274,7 +274,7 @@ public:
return true;
if (errorMessage) {
*errorMessage = QCoreApplication::translate("LanguageServerProtocol::Request",
- "No id set in '%1'").arg(this->method());
+ "No ID set in \"%1\".").arg(this->method());
}
return false;
}
diff --git a/src/libs/languageserverprotocol/languagefeatures.cpp b/src/libs/languageserverprotocol/languagefeatures.cpp
index 6581588201..8009ed1ebd 100644
--- a/src/libs/languageserverprotocol/languagefeatures.cpp
+++ b/src/libs/languageserverprotocol/languagefeatures.cpp
@@ -331,7 +331,7 @@ bool MarkedString::isValid(QStringList *errorHierarchy) const
*errorHierarchy << QCoreApplication::translate(
"LanguageServerProtocol::MarkedString",
"MarkedString should be either MarkedLanguageString, "
- "MarkupContent or QList<MarkedLanguageString>");
+ "MarkupContent, or QList<MarkedLanguageString>.");
}
return false;
}
@@ -356,7 +356,7 @@ bool DocumentFormattingProperty::isValid(QStringList *error) const
if (error) {
*error << QCoreApplication::translate(
"LanguageServerProtocol::MarkedString",
- "DocumentFormattingProperty should be either bool, double or QString");
+ "DocumentFormattingProperty should be either bool, double, or QString.");
}
return false;
}
diff --git a/src/libs/languageserverprotocol/lsptypes.cpp b/src/libs/languageserverprotocol/lsptypes.cpp
index c76d4ff6dd..286732d16b 100644
--- a/src/libs/languageserverprotocol/lsptypes.cpp
+++ b/src/libs/languageserverprotocol/lsptypes.cpp
@@ -136,7 +136,7 @@ bool MarkupOrString::isValid(QStringList *error) const
return true;
if (error) {
*error << QCoreApplication::translate("LanguageServerProtocoll::MarkupOrString",
- "Expected a string or MarkupContent in MarkupOrString");
+ "Expected a string or MarkupContent in MarkupOrString.");
}
return false;
}
diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp
index 192c68bcbd..c05e6cce84 100644
--- a/src/libs/utils/textutils.cpp
+++ b/src/libs/utils/textutils.cpp
@@ -140,5 +140,20 @@ QTextCursor wordStartCursor(const QTextCursor &textCursor)
return cursor;
}
+int utf8NthLineOffset(const QTextDocument *textDocument, const QByteArray &buffer, int line)
+{
+ if (textDocument->characterCount() == buffer.size() + 1)
+ return textDocument->findBlockByNumber(line - 1).position();
+
+ int pos = 0;
+ for (int count = 0; count < line - 1; ++count) {
+ pos = buffer.indexOf('\n', pos);
+ if (pos == -1)
+ return -1;
+ ++pos;
+ }
+ return pos;
+}
+
} // Text
} // Utils
diff --git a/src/libs/utils/textutils.h b/src/libs/utils/textutils.h
index d5414e3194..1d4e8f7ffb 100644
--- a/src/libs/utils/textutils.h
+++ b/src/libs/utils/textutils.h
@@ -29,7 +29,6 @@
#include "utils_global.h"
#include <QString>
-#include <QTextCursor>
QT_FORWARD_DECLARE_CLASS(QTextDocument)
QT_FORWARD_DECLARE_CLASS(QTextCursor)
@@ -37,7 +36,7 @@ QT_FORWARD_DECLARE_CLASS(QTextCursor)
namespace Utils {
namespace Text {
-// line is 1-based, column is 0-based
+// line is 1-based, column is 1-based
QTCREATOR_UTILS_EXPORT bool convertPosition(const QTextDocument *document,
int pos,
int *line, int *column);
@@ -55,42 +54,9 @@ QTCREATOR_UTILS_EXPORT QTextCursor flippedCursor(const QTextCursor &cursor);
QTCREATOR_UTILS_EXPORT QTextCursor wordStartCursor(const QTextCursor &cursor);
-template <class CharacterProvider>
-void moveToPrevChar(CharacterProvider &provider, QTextCursor &cursor)
-{
- cursor.movePosition(QTextCursor::PreviousCharacter);
- while (provider.characterAt(cursor.position()).isSpace())
- cursor.movePosition(QTextCursor::PreviousCharacter);
-}
-
-template <class CharacterProvider>
-bool matchPreviousWord(CharacterProvider &provider, QTextCursor cursor, QString pattern)
-{
- cursor.movePosition(QTextCursor::PreviousWord);
- while (provider.characterAt(cursor.position()) == ':')
- cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor, 2);
-
- int previousWordStart = cursor.position();
- cursor.movePosition(QTextCursor::NextWord);
- moveToPrevChar(provider, cursor);
- QString toMatch = provider.textAt(previousWordStart, cursor.position() - previousWordStart + 1);
-
- pattern = pattern.simplified();
- while (!pattern.isEmpty() && pattern.endsWith(toMatch)) {
- pattern.chop(toMatch.length());
- if (pattern.endsWith(' '))
- pattern.chop(1);
- if (!pattern.isEmpty()) {
- cursor.movePosition(QTextCursor::StartOfWord);
- cursor.movePosition(QTextCursor::PreviousWord);
- previousWordStart = cursor.position();
- cursor.movePosition(QTextCursor::NextWord);
- moveToPrevChar(provider, cursor);
- toMatch = provider.textAt(previousWordStart, cursor.position() - previousWordStart + 1);
- }
- }
- return pattern.isEmpty();
-}
+QTCREATOR_UTILS_EXPORT int utf8NthLineOffset(const QTextDocument *textDocument,
+ const QByteArray &buffer,
+ int line);
} // Text
} // Utils
diff --git a/src/plugins/android/androidtoolchain.cpp b/src/plugins/android/androidtoolchain.cpp
index 7b32e5be69..4ab1f4f0cc 100644
--- a/src/plugins/android/androidtoolchain.cpp
+++ b/src/plugins/android/androidtoolchain.cpp
@@ -451,6 +451,8 @@ AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath,
QList<AndroidToolChain *> toolChainBundle;
for (Core::Id lang : {ProjectExplorer::Constants::CXX_LANGUAGE_ID, ProjectExplorer::Constants::C_LANGUAGE_ID}) {
FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(abi, lang, version);
+ if (!compilerPath.exists())
+ continue;
AndroidToolChain *tc = findToolChain(compilerPath, lang, alreadyKnown);
if (!tc || tc->originalTargetTriple().isEmpty()) {
@@ -464,7 +466,8 @@ AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath,
toolChainBundle.append(tc);
}
- QTC_ASSERT(!toolChainBundle.isEmpty(), continue);
+ if (toolChainBundle.isEmpty())
+ continue;
auto it = newestToolChainForArch.constFind(abi);
if (it == newestToolChainForArch.constEnd())
diff --git a/src/plugins/autotest/autotestplugin.cpp b/src/plugins/autotest/autotestplugin.cpp
index 7fdedda74e..9a513bd2d4 100644
--- a/src/plugins/autotest/autotestplugin.cpp
+++ b/src/plugins/autotest/autotestplugin.cpp
@@ -57,6 +57,7 @@
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <texteditor/texteditor.h>
+#include <texteditor/textdocument.h>
#include <utils/textutils.h>
#include <utils/utilsicons.h>
@@ -261,11 +262,22 @@ void AutotestPlugin::onRunFileTriggered()
runner->prepareToRunTests(TestRunMode::Run);
}
+static QList<TestConfiguration *> testItemsToTestConfigurations(const QList<TestTreeItem *> &items,
+ TestRunMode mode)
+{
+ QList<TestConfiguration *> configs;
+ for (const TestTreeItem * item : items) {
+ if (TestConfiguration *currentConfig = item->asConfiguration(mode))
+ configs << currentConfig;
+ }
+ return configs;
+}
+
void AutotestPlugin::onRunUnderCursorTriggered(TestRunMode mode)
{
- QTextCursor cursor = Utils::Text::wordStartCursor(
- TextEditor::BaseTextEditor::currentTextEditor()->editorWidget()->textCursor());
- cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
+ TextEditor::BaseTextEditor *currentEditor = TextEditor::BaseTextEditor::currentTextEditor();
+ QTextCursor cursor = currentEditor->editorWidget()->textCursor();
+ cursor.select(QTextCursor::WordUnderCursor);
const QString text = cursor.selectedText();
if (text.isEmpty())
return; // Do not trigger when no name under cursor
@@ -274,11 +286,15 @@ void AutotestPlugin::onRunUnderCursorTriggered(TestRunMode mode)
if (testsItems.isEmpty())
return; // Wrong location triggered
- QList<TestConfiguration *> testsToRun;
- for (const TestTreeItem * item : testsItems){
- if (TestConfiguration *cfg = item->asConfiguration(mode))
- testsToRun << cfg;
- }
+ // check whether we have been triggered on a test function definition
+ const uint line = uint(currentEditor->currentLine());
+ const QString &filePath = currentEditor->textDocument()->filePath().toString();
+ const QList<TestTreeItem *> filteredItems = Utils::filtered(testsItems, [&](TestTreeItem *it){
+ return it->line() == line && it->filePath() == filePath;
+ });
+
+ const QList<TestConfiguration *> testsToRun = testItemsToTestConfigurations(
+ filteredItems.size() == 1 ? filteredItems : testsItems, mode);
if (testsToRun.isEmpty()) {
MessageManager::write(tr("Selected test was not found (%1).").arg(text), MessageManager::Flash);
diff --git a/src/plugins/clangcodemodel/clangassistproposalitem.cpp b/src/plugins/clangcodemodel/clangassistproposalitem.cpp
index ed15a006f6..e88970bd6e 100644
--- a/src/plugins/clangcodemodel/clangassistproposalitem.cpp
+++ b/src/plugins/clangcodemodel/clangassistproposalitem.cpp
@@ -198,9 +198,9 @@ void ClangAssistProposalItem::apply(TextDocumentManipulatorInterface &manipulato
QTextCursor cursor = manipulator.textCursorAt(basePosition);
bool abandonParen = false;
- if (::Utils::Text::matchPreviousWord(manipulator, cursor, "&")) {
- ::Utils::Text::moveToPrevChar(manipulator, cursor);
- ::Utils::Text::moveToPrevChar(manipulator, cursor);
+ if (Utils::Text::matchPreviousWord(manipulator, cursor, "&")) {
+ Utils::Text::moveToPreviousWord(manipulator, cursor);
+ Utils::Text::moveToPreviousChar(manipulator, cursor);
const QChar prevChar = manipulator.characterAt(cursor.position());
cursor.setPosition(basePosition);
abandonParen = QString("(;,{}").contains(prevChar);
@@ -211,7 +211,7 @@ void ClangAssistProposalItem::apply(TextDocumentManipulatorInterface &manipulato
if (!abandonParen && ccr.completionKind == CodeCompletion::FunctionDefinitionCompletionKind) {
const CodeCompletionChunk resultType = ccr.chunks.first();
if (resultType.kind == CodeCompletionChunk::ResultType) {
- if (::Utils::Text::matchPreviousWord(manipulator, cursor, resultType.text.toString())) {
+ if (Utils::Text::matchPreviousWord(manipulator, cursor, resultType.text.toString())) {
extraCharacters += methodDefinitionParameters(ccr.chunks);
// To skip the next block.
abandonParen = true;
diff --git a/src/plugins/clangcodemodel/clangbackendcommunicator.cpp b/src/plugins/clangcodemodel/clangbackendcommunicator.cpp
index 6354b50548..4e0c08b672 100644
--- a/src/plugins/clangcodemodel/clangbackendcommunicator.cpp
+++ b/src/plugins/clangcodemodel/clangbackendcommunicator.cpp
@@ -207,9 +207,26 @@ bool BackendCommunicator::isNotWaitingForCompletion() const
return !m_receiver.isExpectingCompletionsMessage();
}
+void BackendCommunicator::setBackendJobsPostponed(bool postponed)
+{
+ if (postponed) {
+ if (!m_postponeBackendJobs)
+ documentVisibilityChanged(Utf8String(), {});
+ ++m_postponeBackendJobs;
+ } else {
+ if (QTC_GUARD(m_postponeBackendJobs > 0))
+ --m_postponeBackendJobs;
+ if (!m_postponeBackendJobs)
+ documentVisibilityChanged();
+ }
+}
+
void BackendCommunicator::documentVisibilityChanged(const Utf8String &currentEditorFilePath,
const Utf8StringVector &visibleEditorsFilePaths)
{
+ if (m_postponeBackendJobs)
+ return;
+
const DocumentVisibilityChangedMessage message(currentEditorFilePath, visibleEditorsFilePaths);
m_sender->documentVisibilityChanged(message);
}
@@ -459,9 +476,14 @@ void BackendCommunicator::initializeBackendWithCurrentData()
void BackendCommunicator::documentsOpened(const FileContainers &fileContainers)
{
- const DocumentsOpenedMessage message(fileContainers,
- currentCppEditorDocumentFilePath(),
- visibleCppEditorDocumentsFilePaths());
+ Utf8String currentDocument;
+ Utf8StringVector visibleDocuments;
+ if (!m_postponeBackendJobs) {
+ currentDocument = currentCppEditorDocumentFilePath();
+ visibleDocuments = visibleCppEditorDocumentsFilePaths();
+ }
+
+ const DocumentsOpenedMessage message(fileContainers, currentDocument, visibleDocuments);
m_sender->documentsOpened(message);
}
diff --git a/src/plugins/clangcodemodel/clangbackendcommunicator.h b/src/plugins/clangcodemodel/clangbackendcommunicator.h
index 7d676cf5a5..9709b60707 100644
--- a/src/plugins/clangcodemodel/clangbackendcommunicator.h
+++ b/src/plugins/clangcodemodel/clangbackendcommunicator.h
@@ -108,6 +108,8 @@ public:
void updateChangeContentStartPosition(const QString &filePath, int position);
bool isNotWaitingForCompletion() const;
+ void setBackendJobsPostponed(bool postponed);
+
private:
void initializeBackend();
void initializeBackendWithCurrentData();
@@ -134,6 +136,7 @@ private:
QTimer m_backendStartTimeOut;
QScopedPointer<ClangBackEnd::ClangCodeModelServerInterface> m_sender;
int m_connectedCount = 0;
+ int m_postponeBackendJobs = 1; // Initial application state is inactive, so no jobs should be run.
};
} // namespace Internal
diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp
index e8d7086662..db68f680bc 100644
--- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp
+++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp
@@ -98,9 +98,9 @@ static void addFunctionOverloadAssistProposalItem(QList<AssistProposalItemInterf
cursor.movePosition(QTextCursor::StartOfWord);
const ClangBackEnd::CodeCompletionChunk resultType = codeCompletion.chunks.first();
- if (::Utils::Text::matchPreviousWord(*interface->textEditorWidget(),
- cursor,
- resultType.text.toString())) {
+ if (Utils::Text::matchPreviousWord(*interface->textEditorWidget(),
+ cursor,
+ resultType.text.toString())) {
// Function definition completion - do not merge completions together.
addAssistProposalItem(items, codeCompletion, name);
} else {
@@ -445,6 +445,12 @@ bool ClangCompletionAssistProcessor::completeInclude(const QTextCursor &cursor)
completeIncludePath(realPath, suffixes);
}
+ auto includesCompare = [](AssistProposalItemInterface *first,
+ AssistProposalItemInterface *second) {
+ return first->text() < second->text();
+ };
+ std::sort(m_completions.begin(), m_completions.end(), includesCompare);
+
return !m_completions.isEmpty();
}
diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
index de02be4686..66abc7913b 100644
--- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
+++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
@@ -53,7 +53,7 @@
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
-#include <QCoreApplication>
+#include <QApplication>
#include <QMenu>
#include <QTextBlock>
@@ -75,6 +75,8 @@ ModelManagerSupportClang::ModelManagerSupportClang()
QTC_CHECK(!m_instance);
m_instance = this;
+ QApplication::instance()->installEventFilter(this);
+
CppTools::CppModelManager::instance()->setCurrentDocumentFilter(
std::make_unique<ClangCurrentDocumentFilter>());
@@ -138,6 +140,11 @@ std::unique_ptr<CppTools::AbstractOverviewModel> ModelManagerSupportClang::creat
return std::make_unique<OverviewModel>();
}
+void ModelManagerSupportClang::setBackendJobsPostponed(bool postponed)
+{
+ m_communicator.setBackendJobsPostponed(postponed);
+}
+
CppTools::BaseEditorDocumentProcessor *ModelManagerSupportClang::createEditorDocumentProcessor(
TextEditor::TextDocument *baseTextDocument)
{
@@ -211,6 +218,20 @@ void ModelManagerSupportClang::connectToWidgetsMarkContextMenuRequested(QWidget
}
}
+bool ModelManagerSupportClang::eventFilter(QObject *obj, QEvent *e)
+{
+ if (obj == QApplication::instance() && e->type() == QEvent::ApplicationStateChange) {
+ switch (QApplication::applicationState()) {
+ case Qt::ApplicationInactive: setBackendJobsPostponed(true); break;
+ case Qt::ApplicationActive: setBackendJobsPostponed(false); break;
+ default:
+ QTC_CHECK(false && "Unexpected Qt::ApplicationState");
+ }
+ }
+
+ return false;
+}
+
void ModelManagerSupportClang::onEditorOpened(Core::IEditor *editor)
{
QTC_ASSERT(editor, return);
diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h
index e11191006f..9578804ebb 100644
--- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h
+++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h
@@ -72,6 +72,7 @@ public:
CppTools::FollowSymbolInterface &followSymbolInterface() override;
CppTools::RefactoringEngineInterface &refactoringEngineInterface() override;
std::unique_ptr<CppTools::AbstractOverviewModel> createOverviewModel() override;
+ void setBackendJobsPostponed(bool postponed) override;
BackendCommunicator &communicator();
QString dummyUiHeaderOnDiskDirPath() const;
@@ -82,6 +83,8 @@ public:
static ModelManagerSupportClang *instance();
private:
+ bool eventFilter(QObject *obj, QEvent *e) override;
+
void onEditorOpened(Core::IEditor *editor);
void onEditorClosed(const QList<Core::IEditor *> &editors);
void onCurrentEditorChanged(Core::IEditor *newCurrent);
diff --git a/src/plugins/clangcodemodel/clangutils.h b/src/plugins/clangcodemodel/clangutils.h
index 956f1dee4a..43866e6a9c 100644
--- a/src/plugins/clangcodemodel/clangutils.h
+++ b/src/plugins/clangcodemodel/clangutils.h
@@ -29,6 +29,8 @@
#include <cpptools/projectpart.h>
+#include <QTextCursor>
+
QT_BEGIN_NAMESPACE
class QTextBlock;
QT_END_NAMESPACE
@@ -66,5 +68,53 @@ QString diagnosticCategoryPrefixRemoved(const QString &text);
void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo);
+namespace Text {
+
+template <class CharacterProvider>
+void moveToPreviousChar(CharacterProvider &provider, QTextCursor &cursor)
+{
+ cursor.movePosition(QTextCursor::PreviousCharacter);
+ while (provider.characterAt(cursor.position()).isSpace())
+ cursor.movePosition(QTextCursor::PreviousCharacter);
+}
+
+template <class CharacterProvider>
+void moveToPreviousWord(CharacterProvider &provider, QTextCursor &cursor)
+{
+ cursor.movePosition(QTextCursor::PreviousWord);
+ while (provider.characterAt(cursor.position()) == ':')
+ cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor, 2);
+}
+
+template <class CharacterProvider>
+bool matchPreviousWord(CharacterProvider &provider, QTextCursor cursor, QString pattern)
+{
+ cursor.movePosition(QTextCursor::PreviousWord);
+ while (provider.characterAt(cursor.position()) == ':')
+ cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor, 2);
+
+ int previousWordStart = cursor.position();
+ cursor.movePosition(QTextCursor::NextWord);
+ moveToPreviousChar(provider, cursor);
+ QString toMatch = provider.textAt(previousWordStart, cursor.position() - previousWordStart + 1);
+
+ pattern = pattern.simplified();
+ while (!pattern.isEmpty() && pattern.endsWith(toMatch)) {
+ pattern.chop(toMatch.length());
+ if (pattern.endsWith(' '))
+ pattern.chop(1);
+ if (!pattern.isEmpty()) {
+ cursor.movePosition(QTextCursor::StartOfWord);
+ cursor.movePosition(QTextCursor::PreviousWord);
+ previousWordStart = cursor.position();
+ cursor.movePosition(QTextCursor::NextWord);
+ moveToPreviousChar(provider, cursor);
+ toMatch = provider.textAt(previousWordStart, cursor.position() - previousWordStart + 1);
+ }
+ }
+ return pattern.isEmpty();
+}
+
+} // namespace Text
} // namespace Utils
} // namespace Clang
diff --git a/src/plugins/clangformat/clangformat.pro b/src/plugins/clangformat/clangformat.pro
index c2e2edd49f..74331b9e5f 100644
--- a/src/plugins/clangformat/clangformat.pro
+++ b/src/plugins/clangformat/clangformat.pro
@@ -24,7 +24,8 @@ HEADERS = \
clangformatconfigwidget.h \
clangformatindenter.h \
clangformatplugin.h \
- clangformatconstants.h
+ clangformatconstants.h \
+ clangformatutils.h
FORMS += \
clangformatconfigwidget.ui
diff --git a/src/plugins/clangformat/clangformat.qbs b/src/plugins/clangformat/clangformat.qbs
index f470951e9d..37bb4c1f64 100644
--- a/src/plugins/clangformat/clangformat.qbs
+++ b/src/plugins/clangformat/clangformat.qbs
@@ -27,10 +27,11 @@ QtcPlugin {
"clangformatconfigwidget.cpp",
"clangformatconfigwidget.h",
"clangformatconfigwidget.ui",
+ "clangformatconstants.h",
"clangformatindenter.cpp",
"clangformatindenter.h",
"clangformatplugin.cpp",
"clangformatplugin.h",
- "clangformatconstants.h",
+ "clangformatutils.h",
]
}
diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp
index 60d58909e3..d2daa3adf7 100644
--- a/src/plugins/clangformat/clangformatconfigwidget.cpp
+++ b/src/plugins/clangformat/clangformatconfigwidget.cpp
@@ -25,6 +25,8 @@
#include "clangformatconfigwidget.h"
+
+#include "clangformatutils.h"
#include "ui_clangformatconfigwidget.h"
#include <clang/Format/Format.h>
@@ -40,23 +42,6 @@
using namespace ProjectExplorer;
namespace ClangFormat {
-namespace Internal {
-
-static void createGlobalClangFormatFileIfNeeded(const QString &settingsDir)
-{
- const QString fileName = settingsDir + "/.clang-format";
- if (QFile::exists(fileName))
- return;
-
- QFile file(fileName);
- if (!file.open(QFile::WriteOnly))
- return;
-
- const clang::format::FormatStyle defaultStyle = clang::format::getLLVMStyle();
- const std::string configuration = clang::format::configurationAsText(defaultStyle);
- file.write(configuration.c_str());
- file.close();
-}
static void readTable(QTableWidget *table, std::istringstream &stream)
{
@@ -137,50 +122,75 @@ ClangFormatConfigWidget::ClangFormatConfigWidget(ProjectExplorer::Project *proje
{
m_ui->setupUi(this);
- std::string testFilePath;
+ initialize();
+}
+
+void ClangFormatConfigWidget::initialize()
+{
+ m_ui->projectHasClangFormat->show();
+ m_ui->clangFormatOptionsTable->show();
+ m_ui->applyButton->show();
+
if (m_project && !m_project->projectDirectory().appendPath(".clang-format").exists()) {
- m_ui->projectHasClangFormat->setText("No .clang-format file for the project");
+ m_ui->projectHasClangFormat->setText(tr("No .clang-format file for the project."));
m_ui->clangFormatOptionsTable->hide();
m_ui->applyButton->hide();
+
+ connect(m_ui->createFileButton, &QPushButton::clicked,
+ this, [this]() {
+ createStyleFileIfNeeded(m_project->projectDirectory());
+ initialize();
+ });
return;
}
+ m_ui->createFileButton->hide();
+
+ std::string testFilePath;
if (m_project) {
+ m_ui->projectHasClangFormat->hide();
testFilePath = m_project->projectDirectory().appendPath("t.cpp").toString().toStdString();
connect(m_ui->applyButton, &QPushButton::clicked, this, &ClangFormatConfigWidget::apply);
} else {
+ const Project *currentProject = SessionManager::startupProject();
+ if (!currentProject
+ || !currentProject->projectDirectory().appendPath(".clang-format").exists()) {
+ m_ui->projectHasClangFormat->hide();
+ } else {
+ m_ui->projectHasClangFormat->setText(
+ tr(" Current project has its own .clang-format file "
+ "and can be configured in Projects > Clang Format."));
+ }
const QString settingsDir = Core::ICore::userResourcePath();
- createGlobalClangFormatFileIfNeeded(settingsDir);
+ createStyleFileIfNeeded(Utils::FileName::fromString(settingsDir));
testFilePath = settingsDir.toStdString() + "/t.cpp";
m_ui->applyButton->hide();
}
+ fillTable(testFilePath);
+}
+
+void ClangFormatConfigWidget::fillTable(const std::string &testFilePath)
+{
llvm::Expected<clang::format::FormatStyle> formatStyle =
- clang::format::getStyle("file", testFilePath, "LLVM", "");
- if (!formatStyle)
- return;
+ clang::format::getStyle("file", testFilePath, "LLVM");
+ std::string configText;
+ bool brokenConfig = false;
+ if (!formatStyle) {
+ handleAllErrors(formatStyle.takeError(), [](const llvm::ErrorInfoBase &) {
+ // do nothing
+ });
+ configText = clang::format::configurationAsText(clang::format::getLLVMStyle());
+ brokenConfig = true;
+ } else {
+ configText = clang::format::configurationAsText(*formatStyle);
+ }
- const std::string configText = clang::format::configurationAsText(*formatStyle);
std::istringstream stream(configText);
-
readTable(m_ui->clangFormatOptionsTable, stream);
+ if (brokenConfig)
+ apply();
- if (m_project) {
- m_ui->projectHasClangFormat->hide();
- return;
- }
-
- const Project *currentProject = SessionManager::startupProject();
- if (!currentProject || !currentProject->projectDirectory().appendPath(".clang-format").exists())
- m_ui->projectHasClangFormat->hide();
-
- connect(SessionManager::instance(), &SessionManager::startupProjectChanged,
- this, [this](ProjectExplorer::Project *project) {
- if (project && project->projectDirectory().appendPath(".clang-format").exists())
- m_ui->projectHasClangFormat->show();
- else
- m_ui->projectHasClangFormat->hide();
- });
}
ClangFormatConfigWidget::~ClangFormatConfigWidget() = default;
@@ -201,5 +211,4 @@ void ClangFormatConfigWidget::apply()
file.close();
}
-} // namespace Internal
} // namespace ClangFormat
diff --git a/src/plugins/clangformat/clangformatconfigwidget.h b/src/plugins/clangformat/clangformatconfigwidget.h
index 004e97128c..5694bd820b 100644
--- a/src/plugins/clangformat/clangformatconfigwidget.h
+++ b/src/plugins/clangformat/clangformatconfigwidget.h
@@ -32,7 +32,6 @@
namespace ProjectExplorer { class Project; }
namespace ClangFormat {
-namespace Internal {
namespace Ui {
class ClangFormatConfigWidget;
@@ -49,9 +48,11 @@ public:
void apply();
private:
+ void initialize();
+ void fillTable(const std::string &testFilePath);
+
ProjectExplorer::Project *m_project;
std::unique_ptr<Ui::ClangFormatConfigWidget> m_ui;
};
-} // namespace Internal
} // namespace ClangFormat
diff --git a/src/plugins/clangformat/clangformatconfigwidget.ui b/src/plugins/clangformat/clangformatconfigwidget.ui
index e3efbea109..41774e133d 100644
--- a/src/plugins/clangformat/clangformatconfigwidget.ui
+++ b/src/plugins/clangformat/clangformatconfigwidget.ui
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
- <class>ClangFormat::Internal::ClangFormatConfigWidget</class>
- <widget class="QWidget" name="ClangFormat::Internal::ClangFormatConfigWidget">
+ <class>ClangFormat::ClangFormatConfigWidget</class>
+ <widget class="QWidget" name="ClangFormat::ClangFormatConfigWidget">
<property name="geometry">
<rect>
<x>0</x>
@@ -29,7 +29,7 @@
<item>
<widget class="QLabel" name="projectHasClangFormat">
<property name="text">
- <string> Current project has its own .clang-format file and can be configured in Projects -&gt; ClangFormat.</string>
+ <string/>
</property>
</widget>
</item>
@@ -39,6 +39,13 @@
<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/clangformatindenter.cpp b/src/plugins/clangformat/clangformatindenter.cpp
index 3164f4ad00..f6cc910be8 100644
--- a/src/plugins/clangformat/clangformatindenter.cpp
+++ b/src/plugins/clangformat/clangformatindenter.cpp
@@ -25,16 +25,21 @@
#include "clangformatindenter.h"
+#include "clangformatutils.h"
+
#include <clang/Format/Format.h>
#include <clang/Tooling/Core/Replacement.h>
#include <coreplugin/icore.h>
+#include <cpptools/cppmodelmanager.h>
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
#include <utils/hostosinfo.h>
+#include <utils/textutils.h>
+#include <utils/qtcassert.h>
#include <llvm/Config/llvm-config.h>
@@ -42,6 +47,8 @@
#include <QFileInfo>
#include <QTextBlock>
+#include <fstream>
+
using namespace clang;
using namespace format;
using namespace llvm;
@@ -50,67 +57,35 @@ using namespace ProjectExplorer;
using namespace TextEditor;
namespace ClangFormat {
-namespace Internal {
namespace {
-void adjustFormatStyleForLineBreak(format::FormatStyle &style,
- int length,
- int prevBlockSize,
- bool prevBlockEndsWithPunctuation)
+void adjustFormatStyleForLineBreak(format::FormatStyle &style)
{
- if (length > 0)
- style.ColumnLimit = prevBlockSize;
- style.AlwaysBreakBeforeMultilineStrings = true;
-#if LLVM_VERSION_MAJOR >= 7
- style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes;
-#else
- style.AlwaysBreakTemplateDeclarations = true;
+ style.DisableFormat = false;
+ style.ColumnLimit = 0;
+#ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED
+ style.KeepLineBreaksForNonEmptyLines = true;
#endif
-
- style.AllowAllParametersOfDeclarationOnNextLine = true;
- style.AllowShortBlocksOnASingleLine = true;
- style.AllowShortCaseLabelsOnASingleLine = true;
- style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
- style.AllowShortIfStatementsOnASingleLine = true;
- style.AllowShortLoopsOnASingleLine = true;
- if (prevBlockEndsWithPunctuation) {
- style.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
- style.BreakBeforeTernaryOperators = false;
- style.BreakConstructorInitializers = FormatStyle::BCIS_AfterColon;
- } else {
- style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
- style.BreakBeforeTernaryOperators = true;
- style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
- }
+ style.MaxEmptyLinesToKeep = 2;
}
Replacements filteredReplacements(const Replacements &replacements,
- unsigned int offset,
- unsigned int lengthForFilter,
- int extraOffsetToAdd,
- int prevBlockLength)
+ int offset,
+ int lengthForFilter,
+ int extraOffsetToAdd)
{
Replacements filtered;
for (const Replacement &replacement : replacements) {
- unsigned int replacementOffset = replacement.getOffset();
+ int replacementOffset = static_cast<int>(replacement.getOffset());
if (replacementOffset > offset + lengthForFilter)
break;
- if (offset > static_cast<unsigned int>(prevBlockLength)
- && replacementOffset < offset - static_cast<unsigned int>(prevBlockLength))
- continue;
-
- if (lengthForFilter == 0 && replacement.getReplacementText().find('\n') == std::string::npos
- && filtered.empty()) {
- continue;
- }
-
if (replacementOffset + 1 >= offset)
- replacementOffset += static_cast<unsigned int>(extraOffsetToAdd);
+ replacementOffset += extraOffsetToAdd;
Error error = filtered.add(Replacement(replacement.getFilePath(),
- replacementOffset,
+ static_cast<unsigned int>(replacementOffset),
replacement.getLength(),
replacement.getReplacementText()));
// Throws if error is not checked.
@@ -120,92 +95,83 @@ Replacements filteredReplacements(const Replacements &replacements,
return filtered;
}
-std::string assumedFilePath()
+Utils::FileName styleConfigPath()
{
const Project *project = SessionManager::startupProject();
if (project && project->projectDirectory().appendPath(".clang-format").exists())
- return project->projectDirectory().appendPath("test.cpp").toString().toStdString();
+ return project->projectDirectory();
- return QString(Core::ICore::userResourcePath() + "/test.cpp").toStdString();
+ return Utils::FileName::fromString(Core::ICore::userResourcePath());
}
-FormatStyle formatStyle()
+FormatStyle formatStyle(Utils::FileName styleConfigPath)
{
- Expected<FormatStyle> style = format::getStyle("file", assumedFilePath(), "none", "");
+ createStyleFileIfNeeded(styleConfigPath);
+
+ Expected<FormatStyle> style = format::getStyle(
+ "file", styleConfigPath.appendPath("test.cpp").toString().toStdString(), "LLVM");
if (style)
return *style;
- return FormatStyle();
-}
-Replacements replacements(const std::string &buffer,
- unsigned int offset,
- unsigned int length,
- bool blockFormatting = false,
- const QChar &typedChar = QChar::Null,
- int extraOffsetToAdd = 0,
- int prevBlockLength = 1,
- bool prevBlockEndsWithPunctuation = false)
-{
- FormatStyle style = formatStyle();
+ handleAllErrors(style.takeError(), [](const ErrorInfoBase &) {
+ // do nothing
+ });
- if (blockFormatting && typedChar == QChar::Null)
- adjustFormatStyleForLineBreak(style, length, prevBlockLength, prevBlockEndsWithPunctuation);
+ return format::getLLVMStyle();
+}
- std::vector<Range> ranges{{offset, length}};
- FormattingAttemptStatus status;
+void trimFirstNonEmptyBlock(const QTextBlock &currentBlock)
+{
+ QTextBlock prevBlock = currentBlock.previous();
+ while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty())
+ prevBlock = prevBlock.previous();
- Replacements replacements = reformat(style, buffer, ranges, assumedFilePath(), &status);
+ if (prevBlock.text().trimmed().isEmpty())
+ return;
- if (!status.FormatComplete)
- Replacements();
+ const QString initialText = prevBlock.text();
+ if (!initialText.at(initialText.size() - 1).isSpace())
+ return;
- unsigned int lengthForFilter = 0;
- if (!blockFormatting)
- lengthForFilter = length;
+ int extraSpaceCount = 1;
+ for (int i = initialText.size() - 2; i >= 0; --i) {
+ if (!initialText.at(i).isSpace())
+ break;
+ ++extraSpaceCount;
+ }
- return filteredReplacements(replacements,
- offset,
- lengthForFilter,
- extraOffsetToAdd,
- prevBlockLength);
+ QTextCursor cursor(prevBlock);
+ cursor.beginEditBlock();
+ cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor,
+ initialText.size() - extraSpaceCount);
+ cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, extraSpaceCount);
+ cursor.removeSelectedText();
+ cursor.endEditBlock();
}
-void applyReplacements(QTextDocument *doc,
- const std::string &stdStrBuffer,
- const tooling::Replacements &replacements,
- int totalShift)
+// Returns the total langth of previous lines with pure whitespace.
+int previousEmptyLinesLength(const QTextBlock &currentBlock)
{
- if (replacements.empty())
- return;
-
- QTextCursor editCursor(doc);
- int fullOffsetDiff = 0;
- for (const Replacement &replacement : replacements) {
- const int utf16Offset
- = QString::fromStdString(stdStrBuffer.substr(0, replacement.getOffset())).length()
- + totalShift + fullOffsetDiff;
- const int utf16Length = QString::fromStdString(stdStrBuffer.substr(replacement.getOffset(),
- replacement.getLength()))
- .length();
- const QString replacementText = QString::fromStdString(replacement.getReplacementText());
-
- editCursor.beginEditBlock();
- editCursor.setPosition(utf16Offset);
- editCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, utf16Length);
- editCursor.removeSelectedText();
- editCursor.insertText(replacementText);
- editCursor.endEditBlock();
- fullOffsetDiff += replacementText.length() - utf16Length;
+ int length{0};
+ QTextBlock prevBlock = currentBlock.previous();
+ while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty()) {
+ length += prevBlock.text().length() + 1;
+ prevBlock = prevBlock.previous();
}
+
+ return length;
}
-// Returns offset shift.
-int modifyToIndentEmptyLines(QString &buffer, int &offset, int &length, const QTextBlock &block)
+void modifyToIndentEmptyLines(QByteArray &buffer, int &offset, int &length, const QTextBlock &block)
{
+ const QString blockText = block.text().trimmed();
+ const bool closingParenBlock = blockText.startsWith(')');
+ if (length != 0 && !closingParenBlock)
+ return;
+
//This extra text works for the most cases.
- QString extraText("a;");
+ QByteArray extraText("a;");
- const QString blockText = block.text().trimmed();
// Search for previous character
QTextBlock prevBlock = block.previous();
while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty())
@@ -213,7 +179,6 @@ int modifyToIndentEmptyLines(QString &buffer, int &offset, int &length, const QT
if (prevBlock.text().endsWith(','))
extraText = "int a,";
- const bool closingParenBlock = blockText.startsWith(')');
if (closingParenBlock) {
if (prevBlock.text().endsWith(','))
extraText = "int a";
@@ -221,97 +186,151 @@ int modifyToIndentEmptyLines(QString &buffer, int &offset, int &length, const QT
extraText = "&& a";
}
- if (length == 0 || closingParenBlock) {
- length += extraText.length();
- buffer.insert(offset, extraText);
- }
-
- if (blockText.startsWith('}')) {
- buffer.insert(offset - 1, extraText);
- offset += extraText.size();
- return extraText.size();
- }
-
- return 0;
+ length += extraText.length();
+ buffer.insert(offset, extraText);
}
-// Returns first non-empty block (searches from current block backwards).
-QTextBlock clearFirstNonEmptyBlockFromExtraSpaces(const QTextBlock &currentBlock)
+static const int kMaxLinesFromCurrentBlock = 200;
+
+Replacements replacements(QByteArray buffer,
+ int utf8Offset,
+ int utf8Length,
+ const QTextBlock *block = nullptr,
+ const QChar &typedChar = QChar::Null)
{
- QTextBlock prevBlock = currentBlock.previous();
- while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty())
- prevBlock = prevBlock.previous();
+ Utils::FileName stylePath = styleConfigPath();
+ FormatStyle style = formatStyle(stylePath);
+
+ int extraOffset = 0;
+ if (block) {
+ if (block->blockNumber() > kMaxLinesFromCurrentBlock) {
+ extraOffset = Utils::Text::utf8NthLineOffset(
+ block->document(), buffer, block->blockNumber() - kMaxLinesFromCurrentBlock);
+ }
+ buffer = buffer.mid(extraOffset,
+ std::min(buffer.size(), utf8Offset + kMaxLinesFromCurrentBlock)
+ - extraOffset);
+ utf8Offset -= extraOffset;
- if (prevBlock.text().trimmed().isEmpty())
- return prevBlock;
+ const int emptySpaceLength = previousEmptyLinesLength(*block);
+ utf8Offset -= emptySpaceLength;
+ buffer.remove(utf8Offset, emptySpaceLength);
- const QString initialText = prevBlock.text();
- if (!initialText.at(initialText.length() - 1).isSpace())
- return prevBlock;
+ extraOffset += emptySpaceLength;
- QTextCursor cursor(prevBlock);
- cursor.beginEditBlock();
- cursor.movePosition(QTextCursor::EndOfBlock);
- cursor.movePosition(QTextCursor::Left);
+ adjustFormatStyleForLineBreak(style);
+ if (typedChar == QChar::Null)
+ modifyToIndentEmptyLines(buffer, utf8Offset, utf8Length, *block);
+ }
- while (cursor.positionInBlock() >= 0 && initialText.at(cursor.positionInBlock()).isSpace())
- cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);
- if (cursor.hasSelection())
- cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
- cursor.removeSelectedText();
- cursor.endEditBlock();
- return prevBlock;
+ std::vector<Range> ranges{{static_cast<unsigned int>(utf8Offset),
+ static_cast<unsigned int>(utf8Length)}};
+ FormattingAttemptStatus status;
+
+ const std::string assumedFilePath
+ = stylePath.appendPath("test.cpp").toString().toStdString();
+ Replacements replacements = reformat(style, buffer.data(), ranges, assumedFilePath, &status);
+
+ if (!status.FormatComplete)
+ Replacements();
+
+ int lengthForFilter = 0;
+ if (block == nullptr)
+ lengthForFilter = utf8Length;
+
+ return filteredReplacements(replacements,
+ utf8Offset,
+ lengthForFilter,
+ extraOffset);
}
-// Returns the total langth of previous lines with pure whitespace.
-int previousEmptyLinesLength(const QTextBlock &currentBlock)
+Utils::LineColumn utf16LineColumn(const QTextBlock &block,
+ int blockOffsetUtf8,
+ const QByteArray &utf8Buffer,
+ int utf8Offset)
{
- int length{0};
- QTextBlock prevBlock = currentBlock.previous();
- while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty()) {
- length += prevBlock.text().length() + 1;
- prevBlock = prevBlock.previous();
+ if (utf8Offset < blockOffsetUtf8 - 1)
+ return Utils::LineColumn();
+
+ if (utf8Offset == blockOffsetUtf8 - 1) {
+ const int lineStart = utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1;
+ const QByteArray lineText = utf8Buffer.mid(lineStart, utf8Offset - lineStart);
+ return Utils::LineColumn(block.blockNumber(), QString::fromUtf8(lineText).size() + 1);
}
- return length;
-}
+ int pos = blockOffsetUtf8;
+ int prevPos = pos;
+ int line = block.blockNumber(); // Start with previous line.
+ while (pos != -1 && pos <= utf8Offset) {
+ // Find the first pos which comes after offset and take the previous line.
+ ++line;
+ prevPos = pos;
+ pos = utf8Buffer.indexOf('\n', pos);
+ if (pos != -1)
+ ++pos;
+ }
-static constexpr const int MinCharactersBeforeCurrentInBuffer = 200;
-static constexpr const int MaxCharactersBeforeCurrentInBuffer = 500;
+ const QByteArray lineText = utf8Buffer.mid(prevPos, utf8Offset - prevPos);
+ return Utils::LineColumn(line, QString::fromUtf8(lineText).size() + 1);
+}
-int startOfIndentationBuffer(const QString &buffer, int start)
+tooling::Replacements utf16Replacements(const QTextBlock &block,
+ int blockOffsetUtf8,
+ const QByteArray &utf8Buffer,
+ const tooling::Replacements &replacements)
{
- if (start < MaxCharactersBeforeCurrentInBuffer)
- return 0;
-
- auto it = buffer.cbegin() + (start - MinCharactersBeforeCurrentInBuffer);
- for (; it != buffer.cbegin() + (start - MaxCharactersBeforeCurrentInBuffer); --it) {
- if (*it == '{') {
- // Find the start of it's line.
- for (auto inner = it;
- inner != buffer.cbegin() + (start - MaxCharactersBeforeCurrentInBuffer);
- --inner) {
- if (*inner == '\n')
- return inner + 1 - buffer.cbegin();
- }
+ tooling::Replacements convertedReplacements;
+ for (const Replacement &replacement : replacements) {
+ const Utils::LineColumn lineColUtf16 = utf16LineColumn(
+ block, blockOffsetUtf8, utf8Buffer, static_cast<int>(replacement.getOffset()));
+ if (!lineColUtf16.isValid())
+ continue;
+ const int utf16Offset = Utils::Text::positionInText(block.document(),
+ lineColUtf16.line,
+ lineColUtf16.column);
+ const int utf16Length = QString::fromUtf8(
+ utf8Buffer.mid(static_cast<int>(replacement.getOffset()),
+ static_cast<int>(replacement.getLength()))).size();
+ Error error = convertedReplacements.add(
+ Replacement(replacement.getFilePath(),
+ static_cast<unsigned int>(utf16Offset),
+ static_cast<unsigned int>(utf16Length),
+ replacement.getReplacementText()));
+ // Throws if error is not checked.
+ if (error)
break;
- }
}
- return it - buffer.cbegin();
+ return convertedReplacements;
}
-int nextEndingScopePosition(const QString &buffer, int start)
+void applyReplacements(const QTextBlock &block,
+ int blockOffsetUtf8,
+ const QByteArray &utf8Buffer,
+ const tooling::Replacements &replacements)
{
- if (start >= buffer.size() - 1)
- return buffer.size() - 1;
+ if (replacements.empty())
+ return;
- for (auto it = buffer.cbegin() + (start + 1); it != buffer.cend(); ++it) {
- if (*it == '}')
- return it - buffer.cbegin();
- }
+ tooling::Replacements convertedReplacements = utf16Replacements(block,
+ blockOffsetUtf8,
+ utf8Buffer,
+ replacements);
- return buffer.size() - 1;
+ int fullOffsetShift = 0;
+ QTextCursor editCursor(block);
+ for (const Replacement &replacement : convertedReplacements) {
+ const QString replacementString = QString::fromStdString(replacement.getReplacementText());
+ const int replacementLength = static_cast<int>(replacement.getLength());
+ editCursor.beginEditBlock();
+ editCursor.setPosition(static_cast<int>(replacement.getOffset()) + fullOffsetShift);
+ editCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor,
+ replacementLength);
+ editCursor.removeSelectedText();
+ editCursor.insertText(replacementString);
+ editCursor.endEditBlock();
+ fullOffsetShift += replacementString.length() - replacementLength;
+ }
}
} // anonymous namespace
@@ -342,30 +361,34 @@ void ClangFormatIndenter::indent(QTextDocument *doc,
bool autoTriggered)
{
if (typedChar == QChar::Null && (cursor.hasSelection() || !autoTriggered)) {
- TextEditorWidget *editor = TextEditorWidget::currentTextEditorWidget();
- int offset;
- int length;
+ int utf8Offset;
+ int utf8Length;
+ const QByteArray buffer = doc->toPlainText().toUtf8();
if (cursor.hasSelection()) {
const QTextBlock start = doc->findBlock(cursor.selectionStart());
const QTextBlock end = doc->findBlock(cursor.selectionEnd());
- offset = start.position();
- length = std::max(0, end.position() + end.length() - start.position() - 1);
+ utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, start.blockNumber() + 1);
+ QTC_ASSERT(utf8Offset >= 0, return;);
+ utf8Length =
+ Utils::Text::textAt(
+ QTextCursor(doc),
+ start.position(),
+ std::max(0, end.position() + end.length() - start.position() - 1))
+ .toUtf8().size();
+ applyReplacements(start,
+ utf8Offset,
+ buffer,
+ replacements(buffer, utf8Offset, utf8Length));
} else {
const QTextBlock block = cursor.block();
- offset = block.position();
- length = std::max(0, block.length() - 1);
+ utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, block.blockNumber() + 1);
+ QTC_ASSERT(utf8Offset >= 0, return;);
+ utf8Length = block.text().toUtf8().size();
+ applyReplacements(block,
+ utf8Offset,
+ buffer,
+ replacements(buffer, utf8Offset, utf8Length));
}
- QString buffer = editor->toPlainText();
- const int totalShift = startOfIndentationBuffer(buffer, offset);
- const int cutAtPos = nextEndingScopePosition(buffer, offset + length) + 1;
- buffer = buffer.mid(totalShift, cutAtPos - totalShift);
- offset -= totalShift;
- const std::string stdStrBefore = buffer.left(offset).toStdString();
- const std::string stdStrBuffer = stdStrBefore + buffer.mid(offset).toStdString();
- applyReplacements(doc,
- stdStrBuffer,
- replacements(stdStrBuffer, stdStrBefore.length(), length),
- totalShift);
} else {
indentBlock(doc, cursor.block(), typedChar, tabSettings);
}
@@ -389,46 +412,16 @@ void ClangFormatIndenter::indentBlock(QTextDocument *doc,
if (!editor)
return;
- const QTextBlock prevBlock = clearFirstNonEmptyBlockFromExtraSpaces(block);
+ trimFirstNonEmptyBlock(block);
+ const QByteArray buffer = doc->toPlainText().toUtf8();
+ const int utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, block.blockNumber() + 1);
+ QTC_ASSERT(utf8Offset >= 0, return;);
+ const int utf8Length = block.text().toUtf8().size();
- int offset = block.position();
- int length = std::max(0, block.length() - 1);
- QString buffer = editor->toPlainText();
-
- int emptySpaceLength = previousEmptyLinesLength(block);
- offset -= emptySpaceLength;
- buffer.remove(offset, emptySpaceLength);
-
- int extraPrevBlockLength{0};
- int prevBlockTextLength{1};
- bool prevBlockEndsWithPunctuation = false;
- if (typedChar == QChar::Null) {
- extraPrevBlockLength = modifyToIndentEmptyLines(buffer, offset, length, block);
-
- const QString prevBlockText = prevBlock.text();
- prevBlockEndsWithPunctuation = prevBlockText.size() > 0
- ? prevBlockText.at(prevBlockText.size() - 1).isPunct()
- : false;
- prevBlockTextLength = prevBlockText.size() + 1;
- }
-
- const int totalShift = startOfIndentationBuffer(buffer, offset);
- const int cutAtPos = nextEndingScopePosition(buffer, offset + length) + 1;
- buffer = buffer.mid(totalShift, cutAtPos - totalShift);
- offset -= totalShift;
- const std::string stdStrBefore = buffer.left(offset).toStdString();
- const std::string stdStrBuffer = stdStrBefore + buffer.mid(offset).toStdString();
- applyReplacements(doc,
- stdStrBuffer,
- replacements(stdStrBuffer,
- stdStrBefore.length(),
- length,
- true,
- typedChar,
- emptySpaceLength - extraPrevBlockLength,
- prevBlockTextLength + extraPrevBlockLength,
- prevBlockEndsWithPunctuation),
- totalShift);
+ applyReplacements(block,
+ utf8Offset,
+ buffer,
+ replacements(buffer, utf8Offset, utf8Length, &block, typedChar));
}
int ClangFormatIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings &)
@@ -437,36 +430,14 @@ int ClangFormatIndenter::indentFor(const QTextBlock &block, const TextEditor::Ta
if (!editor)
return -1;
- const QTextBlock prevBlock = clearFirstNonEmptyBlockFromExtraSpaces(block);
-
- int offset = block.position();
- int length = std::max(0, block.length() - 1);
- QString buffer = editor->toPlainText();
-
- int emptySpaceLength = previousEmptyLinesLength(block);
- offset -= emptySpaceLength;
- buffer.replace(offset, emptySpaceLength, "");
- int extraPrevBlockLength = modifyToIndentEmptyLines(buffer, offset, length, block);
-
- const QString prevBlockText = prevBlock.text();
- bool prevBlockEndsWithPunctuation = prevBlockText.size() > 0
- ? prevBlockText.at(prevBlockText.size() - 1).isPunct()
- : false;
-
- const int totalShift = startOfIndentationBuffer(buffer, offset);
- const int cutAtPos = nextEndingScopePosition(buffer, offset + length) + 1;
- buffer = buffer.mid(totalShift, cutAtPos - totalShift);
- offset -= totalShift;
- const std::string stdStrBefore = buffer.left(offset).toStdString();
- const std::string stdStrBuffer = stdStrBefore + buffer.mid(offset).toStdString();
- Replacements toReplace = replacements(stdStrBuffer,
- stdStrBefore.length(),
- length,
- true,
- QChar::Null,
- emptySpaceLength - extraPrevBlockLength,
- prevBlockText.size() + extraPrevBlockLength + 1,
- prevBlockEndsWithPunctuation);
+ trimFirstNonEmptyBlock(block);
+ const QTextDocument *doc = block.document();
+ const QByteArray buffer = doc->toPlainText().toUtf8();
+ const int utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, block.blockNumber() + 1);
+ QTC_ASSERT(utf8Offset >= 0, return 0;);
+ const int utf8Length = block.text().toUtf8().size();
+
+ Replacements toReplace = replacements(buffer, utf8Offset, utf8Length, &block);
if (toReplace.empty())
return -1;
@@ -481,7 +452,7 @@ int ClangFormatIndenter::indentFor(const QTextBlock &block, const TextEditor::Ta
TabSettings ClangFormatIndenter::tabSettings() const
{
- FormatStyle style = formatStyle();
+ FormatStyle style = formatStyle(styleConfigPath());
TabSettings tabSettings;
switch (style.UseTab) {
@@ -495,8 +466,8 @@ TabSettings ClangFormatIndenter::tabSettings() const
tabSettings.m_tabPolicy = TabSettings::MixedTabPolicy;
}
- tabSettings.m_tabSize = style.TabWidth;
- tabSettings.m_indentSize = style.IndentWidth;
+ tabSettings.m_tabSize = static_cast<int>(style.TabWidth);
+ tabSettings.m_indentSize = static_cast<int>(style.IndentWidth);
if (style.AlignAfterOpenBracket)
tabSettings.m_continuationAlignBehavior = TabSettings::ContinuationAlignWithSpaces;
@@ -506,5 +477,4 @@ TabSettings ClangFormatIndenter::tabSettings() const
return tabSettings;
}
-} // namespace Internal
} // namespace ClangFormat
diff --git a/src/plugins/clangformat/clangformatindenter.h b/src/plugins/clangformat/clangformatindenter.h
index 00dde55c16..dfe3b5b95f 100644
--- a/src/plugins/clangformat/clangformatindenter.h
+++ b/src/plugins/clangformat/clangformatindenter.h
@@ -28,7 +28,6 @@
#include <texteditor/indenter.h>
namespace ClangFormat {
-namespace Internal {
class ClangFormatIndenter final : public TextEditor::Indenter
{
@@ -42,9 +41,9 @@ public:
const QTextCursor &cursor,
const TextEditor::TabSettings &tabSettings) override;
void indentBlock(QTextDocument *doc,
- const QTextBlock &block,
- const QChar &typedChar,
- const TextEditor::TabSettings &tabSettings) override;
+ const QTextBlock &block,
+ const QChar &typedChar,
+ const TextEditor::TabSettings &tabSettings) override;
int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override;
bool isElectricCharacter(const QChar &ch) const override;
@@ -53,5 +52,4 @@ public:
TextEditor::TabSettings tabSettings() const override;
};
-} // namespace Internal
} // namespace ClangFormat
diff --git a/src/plugins/clangformat/clangformatplugin.cpp b/src/plugins/clangformat/clangformatplugin.cpp
index 3da6cbfa08..f421b686ac 100644
--- a/src/plugins/clangformat/clangformatplugin.cpp
+++ b/src/plugins/clangformat/clangformatplugin.cpp
@@ -45,6 +45,8 @@
#include <projectexplorer/projectpanelfactory.h>
#include <projectexplorer/target.h>
+#include <clang/Format/Format.h>
+
#include <QAction>
#include <QDebug>
#include <QMainWindow>
@@ -56,7 +58,6 @@
using namespace ProjectExplorer;
namespace ClangFormat {
-namespace Internal {
class ClangFormatOptionsPage : public Core::IOptionsPage
{
@@ -98,7 +99,7 @@ bool ClangFormatPlugin::initialize(const QStringList &arguments, QString *errorS
{
Q_UNUSED(arguments);
Q_UNUSED(errorString);
-
+#ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED
m_optionsPage = std::make_unique<ClangFormatOptionsPage>();
auto panelFactory = new ProjectPanelFactory();
@@ -112,9 +113,8 @@ bool ClangFormatPlugin::initialize(const QStringList &arguments, QString *errorS
CppTools::CppModelManager::instance()->setCppIndenterCreator([]() {
return new ClangFormatIndenter();
});
-
+#endif
return true;
}
-} // namespace Internal
} // namespace ClangFormat
diff --git a/src/plugins/clangformat/clangformatplugin.h b/src/plugins/clangformat/clangformatplugin.h
index e86be64589..00b59cd950 100644
--- a/src/plugins/clangformat/clangformatplugin.h
+++ b/src/plugins/clangformat/clangformatplugin.h
@@ -30,7 +30,6 @@
#include <memory>
namespace ClangFormat {
-namespace Internal {
class ClangFormatOptionsPage;
@@ -50,5 +49,4 @@ private:
std::unique_ptr<ClangFormatOptionsPage> m_optionsPage;
};
-} // namespace Internal
} // namespace ClangTools
diff --git a/src/plugins/clangformat/clangformatutils.h b/src/plugins/clangformat/clangformatutils.h
new file mode 100644
index 0000000000..ad4e21f889
--- /dev/null
+++ b/src/plugins/clangformat/clangformatutils.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 <utils/fileutils.h>
+#include <clang/Format/Format.h>
+
+#include <QFile>
+
+#include <fstream>
+
+namespace ClangFormat {
+
+inline void createStyleFileIfNeeded(Utils::FileName styleConfigPath)
+{
+ const QString configFile = styleConfigPath.appendPath(".clang-format").toString();
+ if (QFile::exists(configFile))
+ return;
+
+ clang::format::FormatStyle newStyle = clang::format::getLLVMStyle();
+ std::fstream newStyleFile(configFile.toStdString(), std::fstream::out);
+ if (newStyleFile.is_open()) {
+ newStyleFile << clang::format::configurationAsText(newStyle);
+ newStyleFile.close();
+ }
+}
+
+}
diff --git a/src/plugins/cppcheck/cppcheckoptions.cpp b/src/plugins/cppcheck/cppcheckoptions.cpp
index 3c16ccfd56..de81af7535 100644
--- a/src/plugins/cppcheck/cppcheckoptions.cpp
+++ b/src/plugins/cppcheck/cppcheckoptions.cpp
@@ -71,7 +71,7 @@ public:
variableChooser->addSupportedWidget (m_customArguments);
m_unusedFunction->setToolTip(tr("Disables multithreaded check."));
- m_ignorePatterns->setToolTip(tr("Comma-separated wildcards of full file paths."
+ m_ignorePatterns->setToolTip(tr("Comma-separated wildcards of full file paths. "
"Files still can be checked if others include them."));
m_addIncludePaths->setToolTip(tr("Can find missing includes but makes "
"checking slower. Use only when needed."));
diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp
index 5db9dd601d..603ff3174b 100644
--- a/src/plugins/cpptools/cppmodelmanager.cpp
+++ b/src/plugins/cpptools/cppmodelmanager.cpp
@@ -1326,6 +1326,11 @@ void CppModelManager::renameIncludes(const QString &oldFileName, const QString &
}
}
+void CppModelManager::setBackendJobsPostponed(bool postponed)
+{
+ d->m_activeModelManagerSupport->setBackendJobsPostponed(postponed);
+}
+
void CppModelManager::onCoreAboutToClose()
{
Core::ProgressManager::cancelTasks(CppTools::Constants::TASK_INDEX);
diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h
index 66cc133146..bafc3b3271 100644
--- a/src/plugins/cpptools/cppmodelmanager.h
+++ b/src/plugins/cpptools/cppmodelmanager.h
@@ -238,6 +238,8 @@ public:
void renameIncludes(const QString &oldFileName, const QString &newFileName);
+ void setBackendJobsPostponed(bool postponed);
+
signals:
/// Project data might be locked while this is emitted.
void aboutToRemoveFiles(const QStringList &files);
diff --git a/src/plugins/cpptools/cppmodelmanagersupport.h b/src/plugins/cpptools/cppmodelmanagersupport.h
index c5457cd51f..f7ff56ca3b 100644
--- a/src/plugins/cpptools/cppmodelmanagersupport.h
+++ b/src/plugins/cpptools/cppmodelmanagersupport.h
@@ -60,6 +60,7 @@ public:
virtual FollowSymbolInterface &followSymbolInterface() = 0;
virtual RefactoringEngineInterface &refactoringEngineInterface() = 0;
virtual std::unique_ptr<AbstractOverviewModel> createOverviewModel() = 0;
+ virtual void setBackendJobsPostponed(bool yesno) = 0;
};
class CPPTOOLS_EXPORT ModelManagerSupportProvider
diff --git a/src/plugins/cpptools/cppmodelmanagersupportinternal.h b/src/plugins/cpptools/cppmodelmanagersupportinternal.h
index cfa326e778..b01f38f4b8 100644
--- a/src/plugins/cpptools/cppmodelmanagersupportinternal.h
+++ b/src/plugins/cpptools/cppmodelmanagersupportinternal.h
@@ -47,6 +47,7 @@ public:
FollowSymbolInterface &followSymbolInterface() final;
RefactoringEngineInterface &refactoringEngineInterface() final;
std::unique_ptr<AbstractOverviewModel> createOverviewModel() final;
+ void setBackendJobsPostponed(bool) final {}
private:
QScopedPointer<CppCompletionAssistProvider> m_completionAssistProvider;
diff --git a/src/plugins/cpptools/cpptools_clangtidychecks.h b/src/plugins/cpptools/cpptools_clangtidychecks.h
index 9fc1fc516d..20dcbdf120 100644
--- a/src/plugins/cpptools/cpptools_clangtidychecks.h
+++ b/src/plugins/cpptools/cpptools_clangtidychecks.h
@@ -50,6 +50,7 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
{
"android-",
{
+ "tring-find-startswith",
{
"cloexec-",
{
@@ -76,7 +77,8 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"open",
"socket"
}
- }
+ },
+ "comparison-in-temp-failure-retry"
}
},
{
@@ -93,16 +95,69 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"bool-pointer-implicit-conversion",
"copy-constructor-init",
"dangling-handle",
+ "exception-escape",
"fold-init-type",
"forward-declaration-namespace",
+ "forwarding-reference-overload",
"inaccurate-erase",
+ "incorrect-roundings",
"integer-division",
- "misplaced-operator-in-strlen-in-alloc",
+ "lambda-function-name",
+ {
+ "macro-",
+ {
+ "parentheses",
+ "repeated-side-effects"
+ }
+ },
+ {
+ "misplaced-",
+ {
+ "operator-in-strlen-in-alloc",
+ "widening-cast"
+ }
+ },
"move-forwarding-reference",
"multiple-statement-macro",
- "string-constructor",
- "suspicious-memset-usage",
+ "narrowing-conversions",
+ "parent-virtual-call",
+ {
+ "sizeof-",
+ {
+ "container",
+ "expression"
+ }
+ },
+ {
+ "string-",
+ {
+ "constructor",
+ "integer-assignment",
+ "literal-with-embedded-nul"
+ }
+ },
+ {
+ "suspicious-",
+ {
+ "enum-usage",
+ "memset-usage",
+ "missing-comma",
+ "semicolon",
+ "string-compare"
+ }
+ },
+ "swapped-arguments",
+ "terminating-continue",
+ "throw-keyword-missing",
"undefined-memory-manipulation",
+ "undelegated-constructor",
+ {
+ "unused-",
+ {
+ "raii",
+ "return-value"
+ }
+ },
"use-after-move",
"virtual-near-miss"
}
@@ -126,14 +181,22 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"fio38-c",
"flp30-c",
"msc30-c",
+ "msc32-c",
"msc50-cpp",
+ "msc51-cpp",
"oop11-cpp"
}
},
{
"clang-analyzer-",
{
- "apiModeling.google.GTest",
+ {
+ "apiModeling.",
+ {
+ "TrustNonnull",
+ "google.GTest"
+ }
+ },
{
"core.",
{
@@ -168,6 +231,7 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
{
"cplusplus.",
{
+ "InnerPointer",
"NewDelete",
"NewDeleteLeaks",
"SelfAssignment"
@@ -207,7 +271,13 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
}
}
},
- "performance.Padding",
+ {
+ "performance.",
+ {
+ "GCDAntipattern",
+ "Padding"
+ }
+ },
"portability.UnixAPI"
}
},
@@ -222,6 +292,7 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"cocoa.",
{
"AtSync",
+ "AutoreleaseWrite",
"ClassRelease",
"Dealloc",
"IncompatibleMethodTypes",
@@ -233,6 +304,7 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"NonNilReturnValue",
"ObjCGenerics",
"RetainCount",
+ "RunLoopAutoreleaseLeak",
"SelfInit",
"SuperDealloc",
"UnusedIvars",
@@ -264,6 +336,9 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"insecureAPI.",
{
"UncheckedReturn",
+ "bcmp",
+ "bcopy",
+ "bzero",
"getpw",
"gets",
"mkstemp",
@@ -306,8 +381,10 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
{
"cppcoreguidelines-",
{
+ "avoid-goto",
"c-copy-assignment-signature",
"interfaces-global-init",
+ "narrowing-conversions",
"no-malloc",
"owning-memory",
{
@@ -343,7 +420,12 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"fuchsia-",
{
"default-arguments",
+ "header-anon-namespaces",
+ "multiple-inheritance",
"overloaded-operator",
+ "restrict-system-includes",
+ "statically-constructed-objects",
+ "trailing-return",
"virtual-inheritance"
}
},
@@ -375,7 +457,6 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"casting",
"function-size",
"namespace-comments",
- "redundant-smartptr-get",
"todo"
}
},
@@ -383,7 +464,6 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"runtime-",
{
"int",
- "member-string-references",
"operator",
"references"
}
@@ -393,6 +473,7 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
{
"hicpp-",
{
+ "avoid-goto",
"braces-around-statements",
"deprecated-headers",
"exception-baseclass",
@@ -401,6 +482,7 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"invalid-access-moved",
"member-init",
"move-const-arg",
+ "multiway-paths-covered",
"named-parameter",
"new-delete-operators",
{
@@ -449,62 +531,19 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"misc-",
{
"definitions-in-headers",
- "forwarding-reference-overload",
- "incorrect-roundings",
- "lambda-function-name",
- {
- "macro-",
- {
- "parentheses",
- "repeated-side-effects"
- }
- },
- {
- "misplaced-",
- {
- "const",
- "widening-cast"
- }
- },
+ "misplaced-const",
"new-delete-overloads",
"non-copyable-objects",
"redundant-expression",
- {
- "sizeof-",
- {
- "container",
- "expression"
- }
- },
"static-assert",
- {
- "string-",
- {
- "compare",
- "integer-assignment",
- "literal-with-embedded-nul"
- }
- },
- {
- "suspicious-",
- {
- "enum-usage",
- "missing-comma",
- "semicolon",
- "string-compare"
- }
- },
- "swapped-arguments",
"throw-by-value-catch-by-reference",
"unconventional-assign-operator",
- "undelegated-constructor",
"uniqueptr-reset-release",
{
"unused-",
{
"alias-decls",
"parameters",
- "raii",
"using-decls"
}
}
@@ -554,6 +593,7 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"nullptr",
"override",
"transparent-functors",
+ "uncaught-exceptions",
"using"
}
}
@@ -609,7 +649,8 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"copy-initialization",
"value-param"
}
- }
+ },
+ "simd-intrinsics"
}
},
{
@@ -646,7 +687,13 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
}
}
},
- "simplify-boolean-expr",
+ {
+ "simplify-",
+ {
+ "boolean-expr",
+ "subscript-expr"
+ }
+ },
{
"static-",
{
@@ -654,7 +701,9 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"definition-in-anonymous-namespace"
}
},
- "uniqueptr-delete-release"
+ "string-compare",
+ "uniqueptr-delete-release",
+ "rary-objects"
}
}
}
diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp
index 9a8ba32fa1..db5b6332ed 100644
--- a/src/plugins/debugger/breakhandler.cpp
+++ b/src/plugins/debugger/breakhandler.cpp
@@ -1709,7 +1709,6 @@ void BreakHandler::removeBreakpoint(const Breakpoint &bp)
break;
case BreakpointInserted:
case BreakpointInsertionProceeding:
- bp->setState(BreakpointRemoveRequested);
requestBreakpointRemoval(bp);
break;
case BreakpointNew:
@@ -2565,17 +2564,17 @@ bool BreakpointManager::setData(const QModelIndex &idx, const QVariant &value, i
// setCurrentIndex(index(row, 0)); FIXME
return true;
}
-// if (kev->key() == Qt::Key_Space) {
-// const QModelIndexList selectedIds = ev.selectedRows();
-// if (!selectedIds.isEmpty()) {
-// const GlobalBreakpoints gbps = findBreakpointsByIndex(selectedIds);
-// const bool isEnabled = gbps.isEmpty() || gbps.at(0)->isEnabled();
-// for (GlobalBreakpoint gbp : gbps)
-// gbp->m_parameters.enabled = isEnabled;
+ if (kev->key() == Qt::Key_Space) {
+ const QModelIndexList selectedIds = ev.selectedRows();
+ if (!selectedIds.isEmpty()) {
+ const GlobalBreakpoints gbps = findBreakpointsByIndex(selectedIds);
+ const bool isEnabled = gbps.isEmpty() || gbps.at(0)->isEnabled();
+ for (GlobalBreakpoint gbp : gbps)
+ gbp->setEnabled(!isEnabled);
// scheduleSynchronization();
-// return true;
-// }
-// }
+ return true;
+ }
+ }
}
if (ev.as<QMouseEvent>(QEvent::MouseButtonDblClick)) {
diff --git a/src/plugins/debugger/breakhandler.h b/src/plugins/debugger/breakhandler.h
index 6df2080429..dee8b3e69b 100644
--- a/src/plugins/debugger/breakhandler.h
+++ b/src/plugins/debugger/breakhandler.h
@@ -98,7 +98,7 @@ private:
void updateMarker();
void updateMarkerIcon();
void destroyMarker();
- void scheduleSynchronization();
+// void scheduleSynchronization();
QPointer<DebuggerEngine> usingEngine() const;
bool isEngineRunning() const;
diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp
index 144dafc800..70a6b90914 100644
--- a/src/plugins/debugger/cdb/cdbengine.cpp
+++ b/src/plugins/debugger/cdb/cdbengine.cpp
@@ -224,7 +224,7 @@ void CdbEngine::init()
m_stopMode = NoStopRequested;
m_nextCommandToken = 0;
m_currentBuiltinResponseToken = -1;
- m_operateByInstruction = true; // Default CDB setting.
+ m_lastOperateByInstruction = true; // Default CDB setting.
m_hasDebuggee = false;
m_sourceStepInto = false;
m_watchPointX = m_watchPointY = 0;
@@ -266,14 +266,13 @@ void CdbEngine::init()
CdbEngine::~CdbEngine() = default;
-void CdbEngine::operateByInstructionTriggered(bool operateByInstruction)
+void CdbEngine::adjustOperateByInstruction(bool operateByInstruction)
{
- DebuggerEngine::operateByInstructionTriggered(operateByInstruction);
- if (m_operateByInstruction == operateByInstruction)
+ if (m_lastOperateByInstruction == operateByInstruction)
return;
- m_operateByInstruction = operateByInstruction;
- runCommand({QLatin1String(m_operateByInstruction ? "l-t" : "l+t"), NoFlags});
- runCommand({QLatin1String(m_operateByInstruction ? "l-s" : "l+s"), NoFlags});
+ m_lastOperateByInstruction = operateByInstruction;
+ runCommand({QLatin1String(m_lastOperateByInstruction ? "l-t" : "l+t"), NoFlags});
+ runCommand({QLatin1String(m_lastOperateByInstruction ? "l-s" : "l+s"), NoFlags});
}
bool CdbEngine::canHandleToolTip(const DebuggerToolTipContext &context) const
@@ -521,7 +520,7 @@ void CdbEngine::handleInitialSessionIdle()
const DebuggerRunParameters &rp = runParameters();
if (!rp.commandsAfterConnect.isEmpty())
runCommand({rp.commandsAfterConnect, NoFlags});
- operateByInstructionTriggered(operatesByInstruction());
+ //operateByInstructionTriggered(operatesByInstruction());
// QmlCppEngine expects the QML engine to be connected before any breakpoints are hit
// (attemptBreakpointSynchronization() will be directly called then)
if (rp.breakOnMain) {
@@ -758,10 +757,11 @@ bool CdbEngine::hasCapability(unsigned cap) const
|AdditionalQmlStackCapability);
}
-void CdbEngine::executeStep()
+void CdbEngine::executeStepIn(bool byInstruction)
{
- if (!m_operateByInstruction)
+ if (!m_lastOperateByInstruction)
m_sourceStepInto = true; // See explanation at handleStackTrace().
+ adjustOperateByInstruction(byInstruction);
runCommand({"t", NoFlags}); // Step into-> t (trace)
STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
notifyInferiorRunRequested();
@@ -774,23 +774,14 @@ void CdbEngine::executeStepOut()
notifyInferiorRunRequested();
}
-void CdbEngine::executeNext()
+void CdbEngine::executeStepOver(bool byInstruction)
{
+ adjustOperateByInstruction(byInstruction);
runCommand({"p", NoFlags}); // Step over -> p
STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
notifyInferiorRunRequested();
}
-void CdbEngine::executeStepI()
-{
- executeStep();
-}
-
-void CdbEngine::executeNextI()
-{
- executeNext();
-}
-
void CdbEngine::continueInferior()
{
STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
@@ -1756,8 +1747,9 @@ unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
*message = bp->msgWatchpointByExpressionTriggered(bp->expression(), tid);
else
*message = bp->msgBreakpointTriggered(tid);
- rc |= StopReportStatusMessage|StopNotifyStop;
+ rc |= StopReportStatusMessage;
}
+ rc |= StopNotifyStop;
return rc;
}
if (reason == "exception") {
@@ -1848,7 +1840,7 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT
if (stack.isValid()) {
switch (parseStackTrace(stack, sourceStepInto)) {
case ParseStackStepInto: // Hit on a frame while step into, see parseStackTrace().
- executeStep();
+ executeStepIn(operatesByInstruction());
return;
case ParseStackStepOut: // Hit on a frame with no source while step into.
executeStepOut();
diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h
index c367925fd3..16b71b954b 100644
--- a/src/plugins/debugger/cdb/cdbengine.h
+++ b/src/plugins/debugger/cdb/cdbengine.h
@@ -41,7 +41,7 @@ class CdbCommand;
struct MemoryViewCookie;
class StringInputStream;
-class CdbEngine : public DebuggerEngine
+class CdbEngine : public CppDebuggerEngine
{
Q_OBJECT
@@ -64,11 +64,9 @@ public:
void watchPoint(const QPoint &) override;
void setRegisterValue(const QString &name, const QString &value) override;
- void executeStep() override;
+ void executeStepOver(bool byInstruction) override;
+ void executeStepIn(bool byInstruction) override;
void executeStepOut() override;
- void executeNext() override;
- void executeStepI() override;
- void executeNextI() override;
void continueInferior() override;
void interruptInferior() override;
@@ -113,7 +111,7 @@ private:
void processError();
void processFinished();
void runCommand(const DebuggerCommand &cmd) override;
- void operateByInstructionTriggered(bool) override;
+ void adjustOperateByInstruction(bool);
void createFullBacktrace();
@@ -217,7 +215,7 @@ private:
int m_currentBuiltinResponseToken = -1;
QMap<QString, NormalizedSourceFileName> m_normalizedFileCache;
const QString m_extensionCommandPrefix; //!< Library name used as prefix
- bool m_operateByInstruction = true; // Default CDB setting.
+ bool m_lastOperateByInstruction = true; // Default CDB setting.
bool m_hasDebuggee = false;
enum Wow64State {
wow64Uninitialized,
diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h
index bc9bf9da18..294e806e1a 100644
--- a/src/plugins/debugger/debuggerconstants.h
+++ b/src/plugins/debugger/debuggerconstants.h
@@ -37,6 +37,8 @@ const char MODE_DEBUG[] = "Mode.Debug";
const char C_DEBUGMODE[] = "Debugger.DebugMode";
const char C_CPPDEBUGGER[] = "Gdb Debugger";
const char C_QMLDEBUGGER[] = "Qml/JavaScript Debugger";
+const char C_DEBUGGER_RUNNING[] = "Debugger.Running";
+const char C_DEBUGGER_NOTRUNNING[] = "Debugger.NotRunning";
const char PRESET_PERSPECTIVE_ID[] = "Debugger.Perspective.Preset";
@@ -54,6 +56,7 @@ const char ABORT[] = "Debugger.Abort";
const char STEP[] = "Debugger.StepLine";
const char STEPOUT[] = "Debugger.StepOut";
const char NEXT[] = "Debugger.NextLine";
+const char START_AND_BREAK_ON_MAIN[]= "Debugger.StartAndBreakOnMain";
const char REVERSE[] = "Debugger.ReverseDirection";
const char RESET[] = "Debugger.Reset";
const char OPERATE_BY_INSTRUCTION[] = "Debugger.OperateByInstruction";
diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp
index 992fc8cf3a..301a2801be 100644
--- a/src/plugins/debugger/debuggerengine.cpp
+++ b/src/plugins/debugger/debuggerengine.cpp
@@ -488,7 +488,7 @@ public:
QAction m_breakAction{tr("Toggle Breakpoint")};
QAction m_resetAction{tr("Restart Debugging")};
OptionalAction m_operateByInstructionAction{tr("Operate by Instruction")};
- QAction m_recordForReverseOperationAction{tr("Record information to allpow reversal of Direction")};
+ QAction m_recordForReverseOperationAction{tr("Record Information to Allow Reversal of Direction")};
OptionalAction m_operateInReverseDirectionAction{tr("Reverse Direction")};
OptionalAction m_snapshotAction{tr("Take Snapshot of Process State")};
@@ -526,7 +526,7 @@ void DebuggerEnginePrivate::setupViews()
m_operateByInstructionAction.setIcon(Debugger::Icons::SINGLE_INSTRUCTION_MODE.icon());
m_operateByInstructionAction.setCheckable(true);
m_operateByInstructionAction.setChecked(false);
- m_operateByInstructionAction.setToolTip("<p>" + tr("This switches the debugger to instruction-wise "
+ m_operateByInstructionAction.setToolTip("<p>" + tr("Switches the debugger to instruction-wise "
"operation mode. In this mode, stepping operates on single "
"instructions and the source location view also shows the "
"disassembled instructions."));
@@ -684,18 +684,18 @@ void DebuggerEnginePrivate::setupViews()
connect(&m_abortAction, &QAction::triggered,
m_engine, &DebuggerEngine::abortDebugger);
- m_resetAction.setToolTip(tr("Restart the debugging session."));
+ m_resetAction.setToolTip(tr("Restarts the debugging session."));
m_resetAction.setIcon(Icons::RESTART_TOOLBAR.icon());
connect(&m_resetAction, &QAction::triggered,
m_engine, &DebuggerEngine::handleReset);
m_stepOverAction.setIcon(Icons::STEP_OVER_TOOLBAR.icon());
connect(&m_stepOverAction, &QAction::triggered,
- m_engine, &DebuggerEngine::handleExecNext);
+ m_engine, &DebuggerEngine::handleExecStepOver);
m_stepIntoAction.setIcon(Icons::STEP_INTO_TOOLBAR.icon());
connect(&m_stepIntoAction, &QAction::triggered,
- m_engine, &DebuggerEngine::handleExecStep);
+ m_engine, &DebuggerEngine::handleExecStepIn);
m_stepOutAction.setIcon(Icons::STEP_OUT_TOOLBAR.icon());
connect(&m_stepOutAction, &QAction::triggered,
@@ -1111,7 +1111,7 @@ void DebuggerEngine::notifyEngineSetupFailed()
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
setState(EngineSetupFailed);
if (d->m_isPrimaryEngine) {
- showMessage(tr("Debugging has failed"), NormalMessageFormat);
+ showMessage(tr("Debugging has failed."), NormalMessageFormat);
d->m_progress.setProgressValue(900);
d->m_progress.reportCanceled();
d->m_progress.reportFinished();
@@ -1472,7 +1472,7 @@ void DebuggerEnginePrivate::updateReverseActions()
m_operateInReverseDirectionAction.setVisible(canReverse);
m_operateInReverseDirectionAction.setEnabled(canReverse && stopped && doesRecord);
m_operateInReverseDirectionAction.setIcon(Icons::DIRECTION_BACKWARD.icon());
- m_operateInReverseDirectionAction.setText(DebuggerEngine::tr("Operate in reverse direction"));
+ m_operateInReverseDirectionAction.setText(DebuggerEngine::tr("Operate in Reverse Direction"));
}
void DebuggerEnginePrivate::cleanupViews()
@@ -1787,14 +1787,14 @@ DebuggerToolTipManager *DebuggerEngine::toolTipManager()
return &d->m_toolTipManager;
}
-bool DebuggerEngine::debuggerActionsEnabled() const
+bool DebuggerEngine::operatesByInstruction() const
{
- return debuggerActionsEnabledHelper(d->m_state);
+ return d->m_operateByInstructionAction.isChecked();
}
-bool DebuggerEngine::operatesByInstruction() const
+bool DebuggerEngine::debuggerActionsEnabled() const
{
- return d->m_operateByInstructionAction.isChecked();
+ return debuggerActionsEnabledHelper(d->m_state);
}
void DebuggerEngine::operateByInstructionTriggered(bool on)
@@ -2212,7 +2212,7 @@ void DebuggerEngine::updateLocalsView(const GdbMi &all)
static int count = 0;
showMessage(QString("<Rebuild Watchmodel %1 @ %2 >")
.arg(++count).arg(LogWindow::logTimeStamp()), LogMiscInput);
- showMessage(tr("Finished retrieving data"), 400, StatusBar);
+ showMessage(tr("Finished retrieving data."), 400, StatusBar);
d->m_toolTipManager.updateToolTips();
@@ -2291,32 +2291,16 @@ void DebuggerEngine::handleReset()
resetInferior();
}
-void DebuggerEngine::handleExecStep()
+void DebuggerEngine::handleExecStepIn()
{
- if (state() == DebuggerNotReady) {
- DebuggerRunTool::setBreakOnMainNextTime();
- ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE);
- } else {
- resetLocation();
- if (operatesByInstruction())
- executeStepI();
- else
- executeStep();
- }
+ resetLocation();
+ executeStepIn(operatesByInstruction());
}
-void DebuggerEngine::handleExecNext()
+void DebuggerEngine::handleExecStepOver()
{
- if (state() == DebuggerNotReady) {
- DebuggerRunTool::setBreakOnMainNextTime();
- ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE);
- } else {
- resetLocation();
- if (operatesByInstruction())
- executeNextI();
- else
- executeNext();
- }
+ resetLocation();
+ executeStepOver(operatesByInstruction());
}
void DebuggerEngine::handleExecStepOut()
diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h
index 05c30078d4..987ca38073 100644
--- a/src/plugins/debugger/debuggerengine.h
+++ b/src/plugins/debugger/debuggerengine.h
@@ -434,8 +434,8 @@ public:
void handleUserStop();
void handleAbort();
void handleReset();
- void handleExecStep();
- void handleExecNext();
+ void handleExecStepIn();
+ void handleExecStepOver();
void handleExecStepOut();
void handleExecReturn();
void handleExecJumpToLine();
@@ -480,11 +480,9 @@ protected:
virtual void resetInferior() {}
virtual void detachDebugger() {}
- virtual void executeStep() {}
+ virtual void executeStepOver(bool /*byInstruction*/ = false) {}
+ virtual void executeStepIn(bool /*byInstruction*/ = false) {}
virtual void executeStepOut() {}
- virtual void executeNext() {}
- virtual void executeStepI() {}
- virtual void executeNextI() {}
virtual void executeReturn() {}
virtual void continueInferior() {}
diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp
index 3489ed59b8..1435147346 100644
--- a/src/plugins/debugger/debuggeritem.cpp
+++ b/src/plugins/debugger/debuggeritem.cpp
@@ -56,7 +56,6 @@ const char DEBUGGER_INFORMATION_DISPLAYNAME[] = "DisplayName";
const char DEBUGGER_INFORMATION_ID[] = "Id";
const char DEBUGGER_INFORMATION_ENGINETYPE[] = "EngineType";
const char DEBUGGER_INFORMATION_AUTODETECTED[] = "AutoDetected";
-const char DEBUGGER_INFORMATION_AUTODETECTION_SOURCE[] = "AutoDetectionSource";
const char DEBUGGER_INFORMATION_VERSION[] = "Version";
const char DEBUGGER_INFORMATION_ABIS[] = "Abis";
const char DEBUGGER_INFORMATION_LASTMODIFIED[] = "LastModified";
@@ -82,7 +81,6 @@ DebuggerItem::DebuggerItem(const QVariantMap &data)
m_workingDirectory = FileName::fromUserInput(data.value(DEBUGGER_INFORMATION_WORKINGDIRECTORY).toString());
m_unexpandedDisplayName = data.value(DEBUGGER_INFORMATION_DISPLAYNAME).toString();
m_isAutoDetected = data.value(DEBUGGER_INFORMATION_AUTODETECTED, false).toBool();
- m_autoDetectionSource = data.value(DEBUGGER_INFORMATION_AUTODETECTION_SOURCE).toString();
m_version = data.value(DEBUGGER_INFORMATION_VERSION).toString();
m_engineType = DebuggerEngineType(data.value(DEBUGGER_INFORMATION_ENGINETYPE,
static_cast<int>(NoEngineType)).toInt());
@@ -252,7 +250,6 @@ QVariantMap DebuggerItem::toMap() const
data.insert(DEBUGGER_INFORMATION_WORKINGDIRECTORY, m_workingDirectory.toString());
data.insert(DEBUGGER_INFORMATION_ENGINETYPE, int(m_engineType));
data.insert(DEBUGGER_INFORMATION_AUTODETECTED, m_isAutoDetected);
- data.insert(DEBUGGER_INFORMATION_AUTODETECTION_SOURCE, m_autoDetectionSource);
data.insert(DEBUGGER_INFORMATION_VERSION, m_version);
data.insert(DEBUGGER_INFORMATION_ABIS, abiNames());
data.insert(DEBUGGER_INFORMATION_LASTMODIFIED, m_lastModified);
@@ -306,11 +303,6 @@ void DebuggerItem::setVersion(const QString &version)
m_version = version;
}
-void DebuggerItem::setAutoDetectionSource(const QString &autoDetectionSource)
-{
- m_autoDetectionSource = autoDetectionSource;
-}
-
void DebuggerItem::setAbis(const QList<Abi> &abis)
{
m_abis = abis;
diff --git a/src/plugins/debugger/debuggeritem.h b/src/plugins/debugger/debuggeritem.h
index e93d30e8b7..20f141600b 100644
--- a/src/plugins/debugger/debuggeritem.h
+++ b/src/plugins/debugger/debuggeritem.h
@@ -81,9 +81,6 @@ public:
QString version() const;
void setVersion(const QString &version);
- QString autoDetectionSource() const { return m_autoDetectionSource; }
- void setAutoDetectionSource(const QString &autoDetectionSource);
-
const QList<ProjectExplorer::Abi> &abis() const { return m_abis; }
void setAbis(const QList<ProjectExplorer::Abi> &abis);
void setAbi(const ProjectExplorer::Abi &abi);
@@ -115,7 +112,6 @@ private:
Utils::FileName m_command;
Utils::FileName m_workingDirectory;
bool m_isAutoDetected = false;
- QString m_autoDetectionSource;
QString m_version;
QList<ProjectExplorer::Abi> m_abis;
QDateTime m_lastModified;
diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp
index c4d1f9df7d..449842e0b9 100644
--- a/src/plugins/debugger/debuggerplugin.cpp
+++ b/src/plugins/debugger/debuggerplugin.cpp
@@ -768,7 +768,7 @@ public:
Action m_interruptAction{tr("Interrupt"), interruptIcon(false), &DebuggerEngine::handleExecInterrupt};
Action m_abortAction{tr("Abort Debugging"), {}, &DebuggerEngine::abortDebugger,
tr("Aborts debugging and resets the debugger to the initial state.")};
- QAction m_stepAction{tr("Step Into")};
+ QAction m_stepInAction{tr("Step Into")};
Action m_stepOutAction{tr("Step Out"), Icons::STEP_OUT.icon(), &DebuggerEngine::handleExecStepOut};
Action m_runToLineAction{tr("Run to Line"), {}, &DebuggerEngine::handleExecRunToLine};
@@ -776,7 +776,8 @@ public:
Action m_jumpToLineAction{tr("Jump to Line"), {}, &DebuggerEngine::handleExecJumpToLine};
// In the Debug menu.
Action m_returnFromFunctionAction{tr("Immediately Return From Inner Function"), {}, &DebuggerEngine::executeReturn};
- QAction m_nextAction{tr("Step Over")};
+ QAction m_stepOverAction{tr("Step Over")};
+ QAction m_startAndBreakOnMain{tr("Start and Break on Main")};
Action m_watchAction{tr("Add Expression Evaluator"), {}, &DebuggerEngine::handleAddToWatchWindow};
Command *m_watchCommand = nullptr;
QAction m_breakAction{tr("Toggle Breakpoint")};
@@ -1012,6 +1013,11 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
QString *errorMessage)
{
Q_UNUSED(errorMessage);
+
+ const Context debuggerRunning(C_DEBUGGER_RUNNING);
+ const Context debuggerNotRunning(C_DEBUGGER_NOTRUNNING);
+ ICore::addAdditionalContext(debuggerNotRunning);
+
m_arguments = arguments;
if (!m_arguments.isEmpty())
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::finishedInitialization,
@@ -1225,34 +1231,37 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
debugMenu->addSeparator();
- cmd = ActionManager::registerAction(&m_nextAction, Constants::NEXT);
+ cmd = ActionManager::registerAction(&m_startAndBreakOnMain,
+ Constants::START_AND_BREAK_ON_MAIN,
+ debuggerNotRunning);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Ctrl+Shift+O") : tr("F10")));
cmd->setAttribute(Command::CA_Hide);
- cmd->setAttribute(Command::CA_UpdateText);
debugMenu->addAction(cmd);
- m_nextAction.setIcon(Icons::STEP_OVER.icon());
- connect(&m_nextAction, &QAction::triggered, this, [] {
- if (DebuggerEngine *engine = EngineManager::currentEngine()) {
- engine->handleExecNext();
- } else {
- DebuggerRunTool::setBreakOnMainNextTime();
- ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, false);
- }
+ connect(&m_startAndBreakOnMain, &QAction::triggered, this, [] {
+ DebuggerRunTool::setBreakOnMainNextTime();
+ ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, false);
+ });
+
+ cmd = ActionManager::registerAction(&m_stepOverAction, Constants::NEXT, debuggerRunning);
+ cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Ctrl+Shift+O") : tr("F10")));
+ cmd->setAttribute(Command::CA_Hide);
+ debugMenu->addAction(cmd);
+ m_stepOverAction.setIcon(Icons::STEP_OVER.icon());
+ connect(&m_stepOverAction, &QAction::triggered, this, [] {
+ DebuggerEngine *engine = EngineManager::currentEngine();
+ QTC_ASSERT(engine, return);
+ engine->handleExecStepOver();
});
- cmd = ActionManager::registerAction(&m_stepAction, Constants::STEP);
+ cmd = ActionManager::registerAction(&m_stepInAction, Constants::STEP, debuggerRunning);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Ctrl+Shift+I") : tr("F11")));
cmd->setAttribute(Command::CA_Hide);
- cmd->setAttribute(Command::CA_UpdateText);
debugMenu->addAction(cmd);
- m_stepAction.setIcon(Icons::STEP_OVER.icon());
- connect(&m_stepAction, &QAction::triggered, this, [] {
- if (DebuggerEngine *engine = EngineManager::currentEngine()) {
- engine->handleExecStep();
- } else {
- DebuggerRunTool::setBreakOnMainNextTime();
- ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, false);
- }
+ m_stepInAction.setIcon(Icons::STEP_INTO.icon());
+ connect(&m_stepInAction, &QAction::triggered, this, [] {
+ DebuggerEngine *engine = EngineManager::currentEngine();
+ QTC_ASSERT(engine, return);
+ engine->handleExecStepIn();
});
@@ -1469,10 +1478,10 @@ void DebuggerPluginPrivate::updatePresetState()
// correspond to the current start up project.
// Step into/next: Start and break at 'main' unless a debugger is running.
QString stepToolTip = canRun ? tr("Start \"%1\" and break at function \"main\"").arg(startupRunConfigName) : whyNot;
- m_stepAction.setToolTip(stepToolTip);
- m_nextAction.setToolTip(stepToolTip);
- m_stepAction.setEnabled(canRun);
- m_nextAction.setEnabled(canRun);
+ m_stepInAction.setEnabled(canRun);
+ m_stepInAction.setToolTip(stepToolTip);
+ m_stepOverAction.setEnabled(canRun);
+ m_stepOverAction.setToolTip(stepToolTip);
m_startAction.setEnabled(canRun);
m_startAction.setIcon(startIcon(false));
m_startAction.setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
@@ -1492,8 +1501,8 @@ void DebuggerPluginPrivate::updatePresetState()
QTC_ASSERT(currentEngine, return);
// We have a current engine, and it belongs to the startup runconfig.
- m_stepAction.setToolTip(QString());
- m_nextAction.setToolTip(QString());
+ m_stepInAction.setToolTip(QString());
+ m_stepOverAction.setToolTip(QString());
// The 'state' bits only affect the fat debug button, not the preset start button.
m_startAction.setIcon(startIcon(false));
@@ -1522,8 +1531,8 @@ void DebuggerPluginPrivate::updatePresetState()
m_debugWithoutDeployAction.setEnabled(false);
m_visibleStartAction.setAction(&m_continueAction);
m_hiddenStopAction.setAction(&m_exitAction);
- m_stepAction.setEnabled(!companionPreventsAction);
- m_nextAction.setEnabled(!companionPreventsAction);
+ m_stepInAction.setEnabled(!companionPreventsAction);
+ m_stepOverAction.setEnabled(!companionPreventsAction);
m_jumpToLineAction.setEnabled(currentEngine->hasCapability(JumpToLineCapability));
m_returnFromFunctionAction.setEnabled(currentEngine->hasCapability(ReturnFromFunctionCapability));
m_detachAction.setEnabled(!isCore);
@@ -1541,8 +1550,8 @@ void DebuggerPluginPrivate::updatePresetState()
m_debugWithoutDeployAction.setEnabled(false);
m_visibleStartAction.setAction(&m_interruptAction);
m_hiddenStopAction.setAction(&m_interruptAction);
- m_stepAction.setEnabled(false);
- m_nextAction.setEnabled(false);
+ m_stepInAction.setEnabled(false);
+ m_stepOverAction.setEnabled(false);
m_jumpToLineAction.setEnabled(false);
m_returnFromFunctionAction.setEnabled(false);
m_detachAction.setEnabled(false);
@@ -1560,8 +1569,8 @@ void DebuggerPluginPrivate::updatePresetState()
m_debugWithoutDeployAction.setEnabled(canRun);
m_visibleStartAction.setAction(&m_startAction);
m_hiddenStopAction.setAction(&m_undisturbableAction);
- m_stepAction.setEnabled(false);
- m_nextAction.setEnabled(false);
+ m_stepInAction.setEnabled(false);
+ m_stepOverAction.setEnabled(false);
m_jumpToLineAction.setEnabled(false);
m_returnFromFunctionAction.setEnabled(false);
m_detachAction.setEnabled(false);
@@ -1579,8 +1588,8 @@ void DebuggerPluginPrivate::updatePresetState()
m_debugWithoutDeployAction.setEnabled(false);
m_visibleStartAction.setAction(&m_exitAction);
m_hiddenStopAction.setAction(&m_exitAction);
- m_stepAction.setEnabled(false);
- m_nextAction.setEnabled(false);
+ m_stepInAction.setEnabled(false);
+ m_stepOverAction.setEnabled(false);
m_jumpToLineAction.setEnabled(false);
m_returnFromFunctionAction.setEnabled(false);
m_detachAction.setEnabled(false);
@@ -1601,8 +1610,8 @@ void DebuggerPluginPrivate::updatePresetState()
m_debugWithoutDeployAction.setEnabled(false);
m_visibleStartAction.setAction(&m_undisturbableAction);
m_hiddenStopAction.setAction(&m_undisturbableAction);
- m_stepAction.setEnabled(false);
- m_nextAction.setEnabled(false);
+ m_stepInAction.setEnabled(false);
+ m_stepOverAction.setEnabled(false);
m_jumpToLineAction.setEnabled(false);
m_returnFromFunctionAction.setEnabled(false);
m_detachAction.setEnabled(false);
@@ -2064,13 +2073,13 @@ void DebuggerPluginPrivate::setInitialState()
m_interruptAction.setEnabled(false);
m_continueAction.setEnabled(false);
- m_stepAction.setEnabled(true);
+ m_stepInAction.setEnabled(true);
m_stepOutAction.setEnabled(false);
m_runToLineAction.setEnabled(false);
m_runToSelectedFunctionAction.setEnabled(true);
m_returnFromFunctionAction.setEnabled(false);
m_jumpToLineAction.setEnabled(false);
- m_nextAction.setEnabled(true);
+ m_stepOverAction.setEnabled(true);
action(AutoDerefPointers)->setEnabled(true);
action(ExpandStack)->setEnabled(false);
diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp
index c2345e2081..7c2bc7ec19 100644
--- a/src/plugins/debugger/debuggerruncontrol.cpp
+++ b/src/plugins/debugger/debuggerruncontrol.cpp
@@ -774,11 +774,6 @@ void DebuggerRunTool::setSolibSearchPath(const QStringList &list)
m_runParameters.solibSearchPath = list;
}
-void DebuggerRunTool::quitDebugger()
-{
- initiateStop();
-}
-
bool DebuggerRunTool::fixupParameters()
{
DebuggerRunParameters &rp = m_runParameters;
diff --git a/src/plugins/debugger/debuggerruncontrol.h b/src/plugins/debugger/debuggerruncontrol.h
index 23d2a5e030..cc4a1f191b 100644
--- a/src/plugins/debugger/debuggerruncontrol.h
+++ b/src/plugins/debugger/debuggerruncontrol.h
@@ -59,8 +59,6 @@ public:
void start() override;
void stop() override;
- void quitDebugger();
-
bool isCppDebugging() const;
bool isQmlDebugging() const;
int portsUsedByDebugger() const;
diff --git a/src/plugins/debugger/disassembleragent.cpp b/src/plugins/debugger/disassembleragent.cpp
index 3244919ebe..1fad2a4b63 100644
--- a/src/plugins/debugger/disassembleragent.cpp
+++ b/src/plugins/debugger/disassembleragent.cpp
@@ -400,6 +400,7 @@ void DisassemblerAgent::updateBreakpointMarker(const Breakpoint &bp)
auto marker = new DisassemblerBreakpointMarker(bp, lineNumber);
d->breakpointMarks.append(marker);
+ QTC_ASSERT(d->document, return);
d->document->addMark(marker);
}
diff --git a/src/plugins/debugger/enginemanager.cpp b/src/plugins/debugger/enginemanager.cpp
index 8e0f102914..4ea21bf99a 100644
--- a/src/plugins/debugger/enginemanager.cpp
+++ b/src/plugins/debugger/enginemanager.cpp
@@ -344,8 +344,13 @@ void EngineManagerPrivate::selectUiForCurrentEngine()
int row = 0;
if (m_currentItem && m_currentItem->m_engine) {
+ ICore::updateAdditionalContexts(Context(Debugger::Constants::C_DEBUGGER_NOTRUNNING),
+ Context(Debugger::Constants::C_DEBUGGER_RUNNING));
perspective = m_currentItem->m_engine->perspective();
m_currentItem->m_engine->updateState(false);
+ } else {
+ ICore::updateAdditionalContexts(Context(Debugger::Constants::C_DEBUGGER_RUNNING),
+ Context(Debugger::Constants::C_DEBUGGER_NOTRUNNING));
}
if (m_currentItem)
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index 167ec5b0e0..ad4b484d68 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -901,7 +901,7 @@ void GdbEngine::handleResultRecord(DebuggerResponse *response)
// there is no debug information. Divert to "-exec-next-step"
showMessage("APPLYING WORKAROUND #3");
notifyInferiorStopOk();
- executeNextI();
+ executeStepOver(true);
} else if (msg.startsWith("Couldn't get registers: No such process.")) {
// Happens on archer-tromey-python 6.8.50.20090910-cvs
// There might to be a race between a process shutting down
@@ -1324,7 +1324,7 @@ void GdbEngine::handleStop1(const GdbMi &data)
if (isSkippableFunction(funcName, fileName)) {
//showMessage(_("SKIPPING ") + funcName);
++stepCounter;
- executeStep();
+ executeStepIn(false);
return;
}
//if (stepCounter)
@@ -1838,25 +1838,32 @@ void GdbEngine::continueInferior()
continueInferiorInternal();
}
-void GdbEngine::executeStep()
+void GdbEngine::executeStepIn(bool byInstruction)
{
CHECK_STATE(InferiorStopOk);
setTokenBarrier();
notifyInferiorRunRequested();
showStatusMessage(tr("Step requested..."), 5000);
+
+ DebuggerCommand cmd;
if (isNativeMixedActiveFrame()) {
- DebuggerCommand cmd("executeStep", RunRequest);
+ cmd.flags = RunRequest;
+ cmd.function = "executeStep";
cmd.callback = CB(handleExecuteStep);
- runCommand(cmd);
+ } else if (byInstruction) {
+ cmd.flags = RunRequest|NeedsFlush;
+ cmd.function = "-exec-step-instruction";
+ if (isReverseDebugging())
+ cmd.function += "--reverse";
+ cmd.callback = CB(handleExecuteContinue);
} else {
- DebuggerCommand cmd;
cmd.flags = RunRequest|NeedsFlush;
cmd.function = "-exec-step";
if (isReverseDebugging())
cmd.function += " --reverse";
cmd.callback = CB(handleExecuteStep);
- runCommand(cmd);
}
+ runCommand(cmd);
}
void GdbEngine::handleExecuteStep(const DebuggerResponse &response)
@@ -1882,7 +1889,7 @@ void GdbEngine::handleExecuteStep(const DebuggerResponse &response)
notifyInferiorRunFailed();
if (isDying())
return;
- executeStepI(); // Fall back to instruction-wise stepping.
+ executeStepIn(true); // Fall back to instruction-wise stepping.
} else if (msg.startsWith("Cannot execute this command while the selected thread is running.")) {
showExecutionError(msg);
notifyInferiorRunFailed();
@@ -1895,21 +1902,6 @@ void GdbEngine::handleExecuteStep(const DebuggerResponse &response)
}
}
-void GdbEngine::executeStepI()
-{
- CHECK_STATE(InferiorStopOk);
- setTokenBarrier();
- notifyInferiorRunRequested();
- showStatusMessage(tr("Step by instruction requested..."), 5000);
- DebuggerCommand cmd;
- cmd.flags = RunRequest|NeedsFlush;
- cmd.function = "-exec-step-instruction";
- if (isReverseDebugging())
- cmd.function += "--reverse";
- cmd.callback = CB(handleExecuteContinue);
- runCommand(cmd);
-}
-
void GdbEngine::executeStepOut()
{
CHECK_STATE(InferiorStopOk);
@@ -1928,23 +1920,29 @@ void GdbEngine::executeStepOut()
}
}
-void GdbEngine::executeNext()
+void GdbEngine::executeStepOver(bool byInstruction)
{
CHECK_STATE(InferiorStopOk);
setTokenBarrier();
notifyInferiorRunRequested();
showStatusMessage(tr("Step next requested..."), 5000);
+
+ DebuggerCommand cmd;
+ cmd.flags = RunRequest;
if (isNativeMixedActiveFrame()) {
- runCommand({"executeNext", RunRequest});
+ cmd.function = "executeNext";
+ } else if (byInstruction) {
+ cmd.function = "-exec-next-instruction";
+ if (isReverseDebugging())
+ cmd.function += " --reverse";
+ cmd.callback = CB(handleExecuteContinue);
} else {
- DebuggerCommand cmd;
- cmd.flags = RunRequest;
cmd.function = "-exec-next";
if (isReverseDebugging())
cmd.function += " --reverse";
cmd.callback = CB(handleExecuteNext);
- runCommand(cmd);
}
+ runCommand(cmd);
}
void GdbEngine::handleExecuteNext(const DebuggerResponse &response)
@@ -1967,7 +1965,7 @@ void GdbEngine::handleExecuteNext(const DebuggerResponse &response)
|| msg.contains("Error accessing memory address ")) {
notifyInferiorRunFailed();
if (!isDying())
- executeNextI(); // Fall back to instruction-wise stepping.
+ executeStepOver(true); // Fall back to instruction-wise stepping.
} else if (msg.startsWith("Cannot execute this command while the selected thread is running.")) {
showExecutionError(msg);
notifyInferiorRunFailed();
@@ -1981,21 +1979,6 @@ void GdbEngine::handleExecuteNext(const DebuggerResponse &response)
}
}
-void GdbEngine::executeNextI()
-{
- CHECK_STATE(InferiorStopOk);
- setTokenBarrier();
- notifyInferiorRunRequested();
- showStatusMessage(tr("Step next instruction requested..."), 5000);
- DebuggerCommand cmd;
- cmd.flags = RunRequest;
- cmd.function = "-exec-next-instruction";
- if (isReverseDebugging())
- cmd.function += " --reverse";
- cmd.callback = CB(handleExecuteContinue);
- runCommand(cmd);
-}
-
static QString addressSpec(quint64 address)
{
return "*0x" + QString::number(address, 16);
diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h
index c93178ee71..097b5ea81c 100644
--- a/src/plugins/debugger/gdb/gdbengine.h
+++ b/src/plugins/debugger/gdb/gdbengine.h
@@ -192,11 +192,9 @@ private: ////////// General Interface //////////
void updateBreakpoint(const Breakpoint &bp) final;
void enableSubBreakpoint(const SubBreakpoint &sbp, bool on) final;
- void executeStep() final;
+ void executeStepIn(bool byInstruction) final;
void executeStepOut() final;
- void executeNext() final;
- void executeStepI() final;
- void executeNextI() final;
+ void executeStepOver(bool byInstruction) final;
void continueInferiorInternal();
void continueInferior() final;
diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp
index 6400908da0..365654034f 100644
--- a/src/plugins/debugger/lldb/lldbengine.cpp
+++ b/src/plugins/debugger/lldb/lldbengine.cpp
@@ -336,16 +336,10 @@ void LldbEngine::interruptInferior()
runCommand({"interruptInferior"});
}
-void LldbEngine::executeStep()
+void LldbEngine::executeStepIn(bool byInstruction)
{
notifyInferiorRunRequested();
- runCommand({"executeStep"});
-}
-
-void LldbEngine::executeStepI()
-{
- notifyInferiorRunRequested();
- runCommand({"executeStepI"});
+ runCommand({QLatin1String(byInstruction ? "executeStepI" : "executeStep")});
}
void LldbEngine::executeStepOut()
@@ -354,16 +348,10 @@ void LldbEngine::executeStepOut()
runCommand({"executeStepOut"});
}
-void LldbEngine::executeNext()
-{
- notifyInferiorRunRequested();
- runCommand({"executeNext"});
-}
-
-void LldbEngine::executeNextI()
+void LldbEngine::executeStepOver(bool byInstruction)
{
notifyInferiorRunRequested();
- runCommand({"executeNextI"});
+ runCommand({QLatin1String(byInstruction ? "executeNextI" : "executeNext")});
}
void LldbEngine::continueInferior()
diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h
index 907a5c2bdf..7d0b01aeba 100644
--- a/src/plugins/debugger/lldb/lldbengine.h
+++ b/src/plugins/debugger/lldb/lldbengine.h
@@ -60,11 +60,9 @@ signals:
void outputReady(const QString &data);
private:
- void executeStep() override;
+ void executeStepIn(bool byInstruction) override;
void executeStepOut() override;
- void executeNext() override;
- void executeStepI() override;
- void executeNextI() override;
+ void executeStepOver(bool byInstruction) override;
void setupEngine() override;
void runEngine() override;
diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp
index 4afd067606..9e6733ae94 100644
--- a/src/plugins/debugger/pdb/pdbengine.cpp
+++ b/src/plugins/debugger/pdb/pdbengine.cpp
@@ -167,14 +167,7 @@ void PdbEngine::interruptInferior()
interruptProcess(m_proc.processId(), GdbEngineType, &error);
}
-void PdbEngine::executeStep()
-{
- notifyInferiorRunRequested();
- notifyInferiorRunOk();
- postDirectCommand("step");
-}
-
-void PdbEngine::executeStepI()
+void PdbEngine::executeStepIn(bool)
{
notifyInferiorRunRequested();
notifyInferiorRunOk();
@@ -188,14 +181,7 @@ void PdbEngine::executeStepOut()
postDirectCommand("return");
}
-void PdbEngine::executeNext()
-{
- notifyInferiorRunRequested();
- notifyInferiorRunOk();
- postDirectCommand("next");
-}
-
-void PdbEngine::executeNextI()
+void PdbEngine::executeStepOver(bool)
{
notifyInferiorRunRequested();
notifyInferiorRunOk();
@@ -269,8 +255,24 @@ void PdbEngine::insertBreakpoint(const Breakpoint &bp)
void PdbEngine::updateBreakpoint(const Breakpoint &bp)
{
- Q_UNUSED(bp);
- QTC_CHECK(false);
+ QTC_ASSERT(bp, return);
+ const BreakpointState state = bp->state();
+ if (QTC_GUARD(state == BreakpointUpdateRequested))
+ notifyBreakpointChangeProceeding(bp);
+ if (bp->responseId().isEmpty()) // FIXME postpone update somehow (QTimer::singleShot?)
+ return;
+
+ // FIXME figure out what needs to be changed (there might be more than enabled state)
+ const BreakpointParameters &requested = bp->requestedParameters();
+ if (requested.enabled != bp->isEnabled()) {
+ if (bp->isEnabled())
+ postDirectCommand("disable " + bp->responseId());
+ else
+ postDirectCommand("enable " + bp->responseId());
+ bp->setEnabled(!bp->isEnabled());
+ }
+ // Pretend it succeeds without waiting for response.
+ notifyBreakpointChangeOk(bp);
}
void PdbEngine::removeBreakpoint(const Breakpoint &bp)
@@ -278,6 +280,10 @@ void PdbEngine::removeBreakpoint(const Breakpoint &bp)
QTC_ASSERT(bp, return);
QTC_CHECK(bp->state() == BreakpointRemoveRequested);
notifyBreakpointRemoveProceeding(bp);
+ if (bp->responseId().isEmpty()) {
+ notifyBreakpointRemoveFailed(bp);
+ return;
+ }
showMessage(QString("DELETING BP %1 IN %2")
.arg(bp->responseId()).arg(bp->fileName()));
postDirectCommand("clear " + bp->responseId());
@@ -504,8 +510,12 @@ void PdbEngine::handleOutput2(const QString &data)
bp->setLineNumber(lineNumber);
bp->adjustMarker();
bp->setPending(false);
- QTC_CHECK(!bp->needsChange());
notifyBreakpointInsertOk(bp);
+ if (bp->needsChange()) {
+ bp->gotoState(BreakpointUpdateRequested, BreakpointInserted);
+ updateBreakpoint(bp);
+// QTC_CHECK(!bp->needsChange());
+ }
}
}
}
diff --git a/src/plugins/debugger/pdb/pdbengine.h b/src/plugins/debugger/pdb/pdbengine.h
index 420e0639c7..57a040d5dc 100644
--- a/src/plugins/debugger/pdb/pdbengine.h
+++ b/src/plugins/debugger/pdb/pdbengine.h
@@ -47,12 +47,9 @@ public:
PdbEngine();
private:
- // DebuggerEngine implementation
- void executeStep() override;
+ void executeStepIn(bool) override;
void executeStepOut() override;
- void executeNext() override;
- void executeStepI() override;
- void executeNextI() override;
+ void executeStepOver(bool) override;
void setupEngine() override;
void runEngine() override;
diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp
index 26647100c9..567a3852e8 100644
--- a/src/plugins/debugger/qml/qmlengine.cpp
+++ b/src/plugins/debugger/qml/qmlengine.cpp
@@ -610,15 +610,7 @@ void QmlEngine::interruptInferior()
showStatusMessage(tr("Waiting for JavaScript engine to interrupt on next statement."));
}
-void QmlEngine::executeStep()
-{
- clearExceptionSelection();
- d->continueDebugging(StepIn);
- notifyInferiorRunRequested();
- notifyInferiorRunOk();
-}
-
-void QmlEngine::executeStepI()
+void QmlEngine::executeStepIn(bool)
{
clearExceptionSelection();
d->continueDebugging(StepIn);
@@ -634,7 +626,7 @@ void QmlEngine::executeStepOut()
notifyInferiorRunOk();
}
-void QmlEngine::executeNext()
+void QmlEngine::executeStepOver(bool)
{
clearExceptionSelection();
d->continueDebugging(Next);
@@ -642,11 +634,6 @@ void QmlEngine::executeNext()
notifyInferiorRunOk();
}
-void QmlEngine::executeNextI()
-{
- executeNext();
-}
-
void QmlEngine::executeRunToLine(const ContextData &data)
{
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h
index 8d407b11ae..df31c3c6c5 100644
--- a/src/plugins/debugger/qml/qmlengine.h
+++ b/src/plugins/debugger/qml/qmlengine.h
@@ -72,11 +72,9 @@ private:
void resetLocation() override;
- void executeStep() override;
+ void executeStepOver(bool) override;
+ void executeStepIn(bool) override;
void executeStepOut() override;
- void executeNext() override;
- void executeStepI() override;
- void executeNextI() override;
void setupEngine() override;
void runEngine() override;
diff --git a/src/plugins/git/TODO.txt b/src/plugins/git/TODO.txt
deleted file mode 100644
index 6f17e577ad..0000000000
--- a/src/plugins/git/TODO.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-Commands:
- - P3:
- - allow to use external viewer instead of greenhouse one
- as these have more functionality usually
-
-GUI:
- - Better diff view
- - Commit action View
- - Able to add further files to commit (list of modified/untracked files)
- - use List for Log (and allow 10+ entries)
-Backend:
- - Don't use forked processes, instead find a library connection like libgit-thin
- - http://repo.or.cz/w/git/libgit-gsoc.git
- - apply to SCM Manager in Greenhouse, currently it's mostly independent
-
-Suggestions:
- - Bjorn: Use a "Summary" Lineedit in the commit dialog to make commits look nicer on gitweb or such.
diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp
index 35340e0731..6f7f83609c 100644
--- a/src/plugins/git/branchmodel.cpp
+++ b/src/plugins/git/branchmodel.cpp
@@ -123,8 +123,6 @@ public:
QStringList fullName(bool includePrefix = false) const
{
- QTC_ASSERT(isLeaf(), return QStringList());
-
QStringList fn;
QList<const BranchNode *> nodes;
const BranchNode *current = this;
diff --git a/src/plugins/git/branchview.cpp b/src/plugins/git/branchview.cpp
index 095cbcedcf..c37bc87abb 100644
--- a/src/plugins/git/branchview.cpp
+++ b/src/plugins/git/branchview.cpp
@@ -37,6 +37,7 @@
#include <coreplugin/documentmanager.h>
#include <coreplugin/inavigationwidgetfactory.h>
#include <utils/elidinglabel.h>
+#include <utils/fancylineedit.h>
#include <utils/navigationtreeview.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
@@ -48,6 +49,7 @@
#include <QMenu>
#include <QMessageBox>
#include <QPoint>
+#include <QSortFilterProxyModel>
#include <QTreeView>
#include <QToolButton>
#include <QVBoxLayout>
@@ -57,6 +59,21 @@ using namespace Core;
namespace Git {
namespace Internal {
+class BranchFilterModel : public QSortFilterProxyModel
+{
+public:
+ BranchFilterModel(QObject *parent) : QSortFilterProxyModel(parent) {}
+protected:
+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
+ {
+ QAbstractItemModel *m = sourceModel();
+ // Filter leaves only. The root node and all intermediate nodes should always be visible
+ if (!sourceParent.isValid() || m->rowCount(m->index(sourceRow, 0, sourceParent)) > 0)
+ return true;
+ return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
+ }
+};
+
BranchView::BranchView() :
m_includeOldEntriesAction(new QAction(tr("Include Old Entries"), this)),
m_includeTagsAction(new QAction(tr("Include Tags"), this)),
@@ -64,7 +81,8 @@ BranchView::BranchView() :
m_refreshButton(new QToolButton(this)),
m_repositoryLabel(new Utils::ElidingLabel(this)),
m_branchView(new Utils::NavigationTreeView(this)),
- m_model(new BranchModel(GitPlugin::client(), this))
+ m_model(new BranchModel(GitPlugin::client(), this)),
+ m_filterModel(new BranchFilterModel(this))
{
m_addButton->setIcon(Utils::Icons::PLUS_TOOLBAR.icon());
m_addButton->setProperty("noArrow", true);
@@ -75,12 +93,21 @@ BranchView::BranchView() :
m_refreshButton->setProperty("noArrow", true);
connect(m_refreshButton, &QToolButton::clicked, this, &BranchView::refreshCurrentRepository);
- m_branchView->setModel(m_model);
m_branchView->setHeaderHidden(true);
setFocus();
m_repositoryLabel->setElideMode(Qt::ElideLeft);
+
+ m_filterModel->setSourceModel(m_model);
+ m_filterModel->setFilterRole(Qt::EditRole);
+ m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ m_branchView->setModel(m_filterModel);
+ auto filterEdit = new Utils::FancyLineEdit(this);
+ filterEdit->setFiltering(true);
+ connect(filterEdit, &Utils::FancyLineEdit::textChanged,
+ m_filterModel, QOverload<const QString &>::of(&BranchFilterModel::setFilterRegExp));
auto layout = new QVBoxLayout(this);
+ layout->addWidget(filterEdit);
layout->addWidget(m_repositoryLabel);
layout->addWidget(m_branchView);
layout->setContentsMargins(0, 2, 0, 0);
@@ -100,7 +127,7 @@ BranchView::BranchView() :
m_branchView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_branchView, &QAbstractItemView::doubleClicked,
- this, &BranchView::log);
+ this, [this](const QModelIndex &idx) { log(m_filterModel->mapToSource(idx)); });
connect(m_branchView, &QWidget::customContextMenuRequested,
this, &BranchView::slotCustomContextMenu);
connect(m_model, &QAbstractItemModel::modelReset,
@@ -161,10 +188,11 @@ void BranchView::resizeColumns()
void BranchView::slotCustomContextMenu(const QPoint &point)
{
- const QModelIndex index = m_branchView->indexAt(point);
- if (!index.isValid())
+ const QModelIndex filteredIndex = m_branchView->indexAt(point);
+ if (!filteredIndex.isValid())
return;
+ const QModelIndex index = m_filterModel->mapToSource(filteredIndex);
const QModelIndex currentBranch = m_model->currentBranch();
const bool currentSelected = index.row() == currentBranch.row();
const bool isLocal = m_model->isLocal(index);
@@ -185,9 +213,9 @@ void BranchView::slotCustomContextMenu(const QPoint &point)
}
if (hasActions) {
if (!currentSelected && (isLocal || isTag))
- contextMenu.addAction(tr("Remove"), this, &BranchView::remove);
+ contextMenu.addAction(tr("Remove..."), this, &BranchView::remove);
if (isLocal || isTag)
- contextMenu.addAction(tr("Rename"), this, &BranchView::rename);
+ contextMenu.addAction(tr("Rename..."), this, &BranchView::rename);
if (!currentSelected)
contextMenu.addAction(tr("Checkout"), this, &BranchView::checkout);
contextMenu.addSeparator();
@@ -246,7 +274,7 @@ QModelIndex BranchView::selectedIndex()
QModelIndexList selected = m_branchView->selectionModel()->selectedIndexes();
if (selected.isEmpty())
return QModelIndex();
- return selected.at(0);
+ return m_filterModel->mapToSource(selected.at(0));
}
bool BranchView::add()
diff --git a/src/plugins/git/branchview.h b/src/plugins/git/branchview.h
index 096510f550..8994cbe1dc 100644
--- a/src/plugins/git/branchview.h
+++ b/src/plugins/git/branchview.h
@@ -46,6 +46,7 @@ namespace Git {
namespace Internal {
class BranchModel;
+class BranchFilterModel;
class BranchView : public QWidget
{
@@ -87,6 +88,7 @@ private:
Utils::ElidingLabel *m_repositoryLabel = nullptr;
Utils::NavigationTreeView *m_branchView = nullptr;
BranchModel *m_model = nullptr;
+ BranchFilterModel *m_filterModel = nullptr;
QString m_repository;
};
diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp
index ea1b229236..cd04e696fc 100644
--- a/src/plugins/help/helpplugin.cpp
+++ b/src/plugins/help/helpplugin.cpp
@@ -274,7 +274,7 @@ HelpPluginPrivate::HelpPluginPrivate()
textEditorContextMenu->addAction(cmd, Core::Constants::G_HELP);
}
- action = new QAction(HelpPlugin::tr("Technical Support"), this);
+ action = new QAction(HelpPlugin::tr("Technical Support..."), this);
cmd = ActionManager::registerAction(action, "Help.TechSupport");
ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_SUPPORT);
connect(action, &QAction::triggered, this, [this] {
diff --git a/src/plugins/languageclient/baseclient.cpp b/src/plugins/languageclient/baseclient.cpp
index 260275e236..7239a7f5fa 100644
--- a/src/plugins/languageclient/baseclient.cpp
+++ b/src/plugins/languageclient/baseclient.cpp
@@ -24,7 +24,6 @@
****************************************************************************/
#include "baseclient.h"
-#include "languageclientcodeassist.h"
#include "languageclientmanager.h"
#include <coreplugin/icore.h>
@@ -63,6 +62,7 @@ static Q_LOGGING_CATEGORY(LOGLSPCLIENTV, "qtc.languageclient.messages", QtWarnin
BaseClient::BaseClient()
: m_id(Core::Id::fromString(QUuid::createUuid().toString()))
+ , m_completionProvider(this)
{
m_buffer.open(QIODevice::ReadWrite | QIODevice::Append);
m_contentHandler.insert(JsonRpcMessageHandler::jsonRpcMimeType(),
@@ -72,6 +72,10 @@ BaseClient::BaseClient()
BaseClient::~BaseClient()
{
m_buffer.close();
+ // FIXME: instead of replacing the completion provider in the text document store the
+ // completion provider as a prioritised list in the text document
+ for (TextEditor::TextDocument *document : m_resetCompletionProvider)
+ document->setCompletionAssistProvider(nullptr);
}
void BaseClient::initialize()
@@ -117,7 +121,7 @@ BaseClient::State BaseClient::state() const
void BaseClient::openDocument(Core::IDocument *document)
{
using namespace TextEditor;
- if (!isSupportedMimeType(document->mimeType()))
+ if (!isSupportedDocument(document))
return;
const FileName &filePath = document->filePath();
const QString method(DidOpenTextDocumentNotification::methodName);
@@ -149,7 +153,11 @@ void BaseClient::openDocument(Core::IDocument *document)
documentContentsChanged(document);
});
if (textDocument) {
- textDocument->setCompletionAssistProvider(new LanguageClientCompletionAssistProvider(this));
+ m_resetCompletionProvider << textDocument;
+ textDocument->setCompletionAssistProvider(&m_completionProvider);
+ connect(textDocument, &QObject::destroyed, this, [this, textDocument]{
+ m_resetCompletionProvider.remove(textDocument);
+ });
if (BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(textDocument)) {
if (QPointer<TextEditorWidget> widget = editor->editorWidget()) {
connect(widget, &TextEditorWidget::cursorPositionChanged, this, [this, widget](){
@@ -489,19 +497,29 @@ void BaseClient::projectClosed(ProjectExplorer::Project *project)
sendContent(change);
}
-void BaseClient::setSupportedMimeType(const QStringList &supportedMimeTypes)
+void BaseClient::setSupportedLanguage(const LanguageFilter &filter)
{
- m_supportedMimeTypes = supportedMimeTypes;
+ m_languagFilter = filter;
}
-bool BaseClient::isSupportedMimeType(const QString &mimeType) const
+bool BaseClient::isSupportedDocument(const Core::IDocument *document) const
{
- return m_supportedMimeTypes.isEmpty() || m_supportedMimeTypes.contains(mimeType);
+ QTC_ASSERT(document, return false);
+ if (m_languagFilter.mimeTypes.isEmpty() || m_languagFilter.mimeTypes.contains(document->mimeType()))
+ return true;
+ auto regexps = Utils::transform(m_languagFilter.filePattern, [](const QString &pattern){
+ return QRegExp(pattern, Utils::HostOsInfo::fileNameCaseSensitivity(), QRegExp::Wildcard);
+ });
+ return Utils::anyOf(regexps, [filePath = document->filePath()](const QRegExp &reg){
+ return reg.exactMatch(filePath.toString()) || reg.exactMatch(filePath.fileName());
+ });
}
-bool BaseClient::needsRestart(const BaseSettings *) const
+bool BaseClient::needsRestart(const BaseSettings *settings) const
{
- return false;
+ QTC_ASSERT(settings, return false);
+ return m_languagFilter.mimeTypes != settings->m_languageFilter.mimeTypes
+ || m_languagFilter.filePattern != settings->m_languageFilter.filePattern;
}
bool BaseClient::reset()
@@ -640,7 +658,7 @@ void BaseClient::intializeCallback(const InitializeResponse &initResponse)
if (optional<ResponseError<InitializeError>> error = initResponse.error()) {
if (error.value().data().has_value()
&& error.value().data().value().retry().value_or(false)) {
- const QString title(tr("Language Server \"%1\" initialize error"));
+ const QString title(tr("Language Server \"%1\" Initialize Error"));
auto result = QMessageBox::warning(Core::ICore::dialogParent(),
title,
error.value().message(),
diff --git a/src/plugins/languageclient/baseclient.h b/src/plugins/languageclient/baseclient.h
index 3ecefcd584..b9e2ee3d4c 100644
--- a/src/plugins/languageclient/baseclient.h
+++ b/src/plugins/languageclient/baseclient.h
@@ -26,6 +26,7 @@
#pragma once
#include "dynamiccapabilities.h"
+#include "languageclientcodeassist.h"
#include "languageclientsettings.h"
#include <coreplugin/id.h>
@@ -104,8 +105,8 @@ public:
const LanguageServerProtocol::IContent &content);
void cancelRequest(const LanguageServerProtocol::MessageId &id);
- void setSupportedMimeType(const QStringList &supportedMimeTypes);
- bool isSupportedMimeType(const QString &mimeType) const;
+ void setSupportedLanguage(const LanguageFilter &filter);
+ bool isSupportedDocument(const Core::IDocument *document) const;
void setName(const QString &name) { m_displayName = name; }
QString name() const { return m_displayName; }
@@ -153,11 +154,13 @@ private:
QHash<QByteArray, ContentHandler> m_contentHandler;
QBuffer m_buffer;
QString m_displayName;
- QStringList m_supportedMimeTypes;
+ LanguageFilter m_languagFilter;
QList<Utils::FileName> m_openedDocument;
Core::Id m_id;
LanguageServerProtocol::ServerCapabilities m_serverCapabilities;
DynamicCapabilities m_dynamicCapabilities;
+ LanguageClientCompletionAssistProvider m_completionProvider;
+ QSet<TextEditor::TextDocument *> m_resetCompletionProvider;
LanguageServerProtocol::BaseMessage m_currentMessage;
QHash<LanguageServerProtocol::DocumentUri, LanguageServerProtocol::MessageId> m_highlightRequests;
int m_restartsLeft = 5;
diff --git a/src/plugins/languageclient/languageclientcodeassist.cpp b/src/plugins/languageclient/languageclientcodeassist.cpp
index 63691b04ca..4a813889f9 100644
--- a/src/plugins/languageclient/languageclientcodeassist.cpp
+++ b/src/plugins/languageclient/languageclientcodeassist.cpp
@@ -69,6 +69,8 @@ public:
bool operator <(const LanguageClientCompletionItem &other) const;
+ bool isPerfectMatch(int pos, QTextDocument *doc) const;
+
private:
CompletionItem m_item;
mutable QString m_sortText;
@@ -194,6 +196,26 @@ bool LanguageClientCompletionItem::operator <(const LanguageClientCompletionItem
return sortText() < other.sortText();
}
+bool LanguageClientCompletionItem::isPerfectMatch(int pos, QTextDocument *doc) const
+{
+ QTC_ASSERT(doc, return false);
+ using namespace Utils::Text;
+ if (auto additionalEdits = m_item.additionalTextEdits()) {
+ if (!additionalEdits.value().isEmpty())
+ return false;
+ }
+ if (auto edit = m_item.textEdit()) {
+ auto range = edit->range();
+ const int start = positionInText(doc, range.start().line() + 1, range.start().character() + 1);
+ const int end = positionInText(doc, range.end().line() + 1, range.end().character() + 1);
+ auto text = textAt(QTextCursor(doc), start, end - start);
+ return text == edit->newText();
+ }
+ const QString textToInsert(m_item.insertText().value_or(text()));
+ const int length = textToInsert.length();
+ return textToInsert == textAt(QTextCursor(doc), pos - length, length);
+}
+
class LanguageClientCompletionModel : public TextEditor::GenericProposalModel
{
public:
@@ -201,6 +223,9 @@ public:
bool isSortable(const QString &/*prefix*/) const override { return true; }
void sort(const QString &/*prefix*/) override;
bool supportsPrefixExpansion() const override { return false; }
+
+ QList<LanguageClientCompletionItem *> items() const
+ { return Utils::static_container_cast<LanguageClientCompletionItem *>(m_currentItems); }
};
void LanguageClientCompletionModel::sort(const QString &/*prefix*/)
@@ -213,16 +238,44 @@ void LanguageClientCompletionModel::sort(const QString &/*prefix*/)
});
}
+class LanguageClientCompletionProposal : public TextEditor::GenericProposal
+{
+public:
+ LanguageClientCompletionProposal(int cursorPos, LanguageClientCompletionModel *model)
+ : TextEditor::GenericProposal(cursorPos, TextEditor::GenericProposalModelPtr(model))
+ , m_model(model)
+ { }
+
+ // IAssistProposal interface
+ bool hasItemsToPropose(const QString &/*text*/, TextEditor::AssistReason reason) const override
+ {
+ if (m_model->size() <= 0 || m_document.isNull())
+ return false;
+
+ return m_model->keepPerfectMatch(reason)
+ || !Utils::anyOf(m_model->items(), [this](LanguageClientCompletionItem *item){
+ return item->isPerfectMatch(m_pos, m_document);
+ });
+ }
+
+ LanguageClientCompletionModel *m_model;
+ QPointer<QTextDocument> m_document;
+ int m_pos = -1;
+};
+
+
class LanguageClientCompletionAssistProcessor : public TextEditor::IAssistProcessor
{
public:
LanguageClientCompletionAssistProcessor(BaseClient *client);
TextEditor::IAssistProposal *perform(const TextEditor::AssistInterface *interface) override;
bool running() override;
+ bool needsRestart() const override { return true; }
private:
void handleCompletionResponse(const Response<CompletionResult, LanguageClientNull> &response);
+ QPointer<QTextDocument> m_document;
QPointer<BaseClient> m_client;
bool m_running = false;
int m_pos = -1;
@@ -247,11 +300,15 @@ TextEditor::IAssistProposal *LanguageClientCompletionAssistProcessor::perform(
{
QTC_ASSERT(m_client, return nullptr);
m_pos = interface->position();
-// const QRegExp regexp("[_a-zA-Z][_a-zA-Z0-9]*"); // FIXME
-// int delta = 0;
-// while (m_pos - delta > 0 && regexp.exactMatch(interface->textAt(m_pos - delta - 1, delta + 1)))
-// ++delta;
-// m_pos -= delta;
+ if (interface->reason() == TextEditor::IdleEditor) {
+ // Trigger an automatic completion request only when we are on a word with more than 2 "identifier" character
+ const QRegExp regexp("[_a-zA-Z0-9]*");
+ int delta = 0;
+ while (m_pos - delta > 0 && regexp.exactMatch(interface->textAt(m_pos - delta - 1, delta + 1)))
+ ++delta;
+ if (delta < 3)
+ return nullptr;
+ }
CompletionRequest completionRequest;
CompletionParams::CompletionContext context;
context.setTriggerKind(interface->reason() == TextEditor::ActivationCharacter
@@ -263,6 +320,7 @@ TextEditor::IAssistProposal *LanguageClientCompletionAssistProcessor::perform(
if (!Utils::Text::convertPosition(interface->textDocument(), m_pos, &line, &column))
return nullptr;
--line; // line is 0 based in the protocol
+ --column; // column is 0 based in the protocol
params.setPosition({line, column});
params.setTextDocument(
DocumentUri::fromFileName(Utils::FileName::fromString(interface->fileName())));
@@ -272,6 +330,7 @@ TextEditor::IAssistProposal *LanguageClientCompletionAssistProcessor::perform(
completionRequest.setParams(params);
m_client->sendContent(completionRequest);
m_running = true;
+ m_document = interface->textDocument();
qCDebug(LOGLSPCOMPLETION) << QTime::currentTime()
<< " : request completions at " << m_pos
<< " by " << assistReasonString(interface->reason());
@@ -309,7 +368,9 @@ void LanguageClientCompletionAssistProcessor::handleCompletionResponse(
model->loadContent(Utils::transform(items, [](const CompletionItem &item){
return static_cast<AssistProposalItemInterface *>(new LanguageClientCompletionItem(item));
}));
- auto proposal = new GenericProposal(m_pos, GenericProposalModelPtr(model));
+ auto proposal = new LanguageClientCompletionProposal(m_pos, model);
+ proposal->m_document = m_document;
+ proposal->m_pos = m_pos;
proposal->setFragile(true);
setAsyncProposalAvailable(proposal);
qCDebug(LOGLSPCOMPLETION) << QTime::currentTime() << " : "
diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp
index f139456aef..31697e1050 100644
--- a/src/plugins/languageclient/languageclientsettings.cpp
+++ b/src/plugins/languageclient/languageclientsettings.cpp
@@ -32,24 +32,33 @@
#include <coreplugin/icore.h>
#include <utils/algorithm.h>
#include <utils/delegates.h>
+#include <utils/fancylineedit.h>
#include <utils/qtcprocess.h>
#include <utils/mimetypes/mimedatabase.h>
#include <languageserverprotocol/lsptypes.h>
#include <QBoxLayout>
+#include <QCheckBox>
#include <QComboBox>
#include <QCompleter>
#include <QCoreApplication>
+#include <QDialog>
+#include <QDialogButtonBox>
+#include <QDir>
#include <QFileInfo>
#include <QHeaderView>
+#include <QLabel>
+#include <QListView>
#include <QPushButton>
#include <QSettings>
-#include <QStyledItemDelegate>
+#include <QSortFilterProxyModel>
+#include <QStringListModel>
#include <QTreeView>
constexpr char nameKey[] = "name";
constexpr char enabledKey[] = "enabled";
constexpr char mimeTypeKey[] = "mimeType";
+constexpr char filePatternKey[] = "filePattern";
constexpr char executableKey[] = "executable";
constexpr char argumentsKey[] = "arguments";
constexpr char settingsGroupKey[] = "LanguageClient";
@@ -57,34 +66,25 @@ constexpr char clientsKey[] = "clients";
namespace LanguageClient {
-class LanguageClientSettingsModel : public QAbstractTableModel
+class LanguageClientSettingsModel : public QAbstractListModel
{
public:
LanguageClientSettingsModel() = default;
~LanguageClientSettingsModel();
// QAbstractItemModel interface
- int rowCount(const QModelIndex &/*parent*/ = QModelIndex()) const override { return m_settings.count(); }
- int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const override { return ColumnCount; }
- QVariant data(const QModelIndex &index, int role) const override;
- QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
- bool removeRows(int row, int count = 1, const QModelIndex &parent = QModelIndex()) override;
- bool insertRows(int row, int count = 1, const QModelIndex &parent = QModelIndex()) override;
- bool setData(const QModelIndex &index, const QVariant &value, int role) override;
- Qt::ItemFlags flags(const QModelIndex &index) const override;
+ int rowCount(const QModelIndex &/*parent*/ = QModelIndex()) const final { return m_settings.count(); }
+ QVariant data(const QModelIndex &index, int role) const final;
+ bool removeRows(int row, int count = 1, const QModelIndex &parent = QModelIndex()) final;
+ bool insertRows(int row, int count = 1, const QModelIndex &parent = QModelIndex()) final;
+ bool setData(const QModelIndex &index, const QVariant &value, int role) final;
+ Qt::ItemFlags flags(const QModelIndex &index) const final;
void reset(const QList<StdIOSettings *> &settings);
QList<StdIOSettings *> settings() const { return m_settings; }
QList<StdIOSettings *> removed() const { return m_removed; }
-
- enum Columns {
- DisplayNameColumn = 0,
- EnabledColumn,
- MimeTypeColumn,
- ExecutableColumn,
- ArgumentsColumn,
- ColumnCount
- };
+ StdIOSettings *settingForIndex(const QModelIndex &index) const;
+ QModelIndex indexForSetting(StdIOSettings *setting) const;
private:
QList<StdIOSettings *> m_settings; // owned
@@ -95,10 +95,18 @@ class LanguageClientSettingsPageWidget : public QWidget
{
public:
LanguageClientSettingsPageWidget(LanguageClientSettingsModel &settings);
+ void currentChanged(const QModelIndex &index);
+ int currentRow() const;
+ void resetCurrentSettings(int row);
+ void applyCurrentSettings();
private:
LanguageClientSettingsModel &m_settings;
- QTreeView *m_view;
+ QTreeView *m_view = nullptr;
+ struct CurrentSettings {
+ StdIOSettings *setting = nullptr;
+ QWidget *widget = nullptr;
+ } m_currentSettings;
void addItem();
void deleteItem();
@@ -123,61 +131,29 @@ private:
QPointer<LanguageClientSettingsPageWidget> m_widget;
};
-class LanguageChooseDelegate : public QStyledItemDelegate
-{
-public:
- QWidget *createEditor(QWidget *parent,
- const QStyleOptionViewItem &option,
- const QModelIndex &index) const override;
- void setEditorData(QWidget *editor, const QModelIndex &index) const override;
-};
-
-QWidget *LanguageChooseDelegate::createEditor(QWidget *parent,
- const QStyleOptionViewItem &option,
- const QModelIndex &index) const
-{
- Q_UNUSED(option);
- Q_UNUSED(index);
- auto editor = new QComboBox(parent);
- editor->addItem(noLanguageFilter);
- editor->addItems(LanguageServerProtocol::languageIds().values());
- return editor;
-}
-
-void LanguageChooseDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
-{
- if (auto comboBox = qobject_cast<QComboBox*>(editor))
- comboBox->setCurrentText(index.data().toString());
-}
-
LanguageClientSettingsPageWidget::LanguageClientSettingsPageWidget(LanguageClientSettingsModel &settings)
: m_settings(settings)
, m_view(new QTreeView())
{
+ auto mainLayout = new QVBoxLayout();
auto layout = new QHBoxLayout();
m_view->setModel(&m_settings);
- m_view->header()->setStretchLastSection(true);
- m_view->setRootIsDecorated(false);
- m_view->setItemsExpandable(false);
+ m_view->setHeaderHidden(true);
+ m_view->setSelectionMode(QAbstractItemView::SingleSelection);
+ m_view->setSelectionBehavior(QAbstractItemView::SelectItems);
+ connect(m_view->selectionModel(), &QItemSelectionModel::currentChanged,
+ this, &LanguageClientSettingsPageWidget::currentChanged);
auto mimeTypes = Utils::transform(Utils::allMimeTypes(), [](const Utils::MimeType &mimeType){
return mimeType.name();
});
- auto mimeTypeCompleter = new QCompleter(mimeTypes);
- mimeTypeCompleter->setCaseSensitivity(Qt::CaseInsensitive);
- mimeTypeCompleter->setFilterMode(Qt::MatchContains);
- m_view->setItemDelegateForColumn(LanguageClientSettingsModel::MimeTypeColumn,
- new Utils::CompleterDelegate(mimeTypeCompleter));
- auto executableDelegate = new Utils::PathChooserDelegate();
- executableDelegate->setExpectedKind(Utils::PathChooser::File);
- executableDelegate->setHistoryCompleter("LanguageClient.ServerPathHistory");
- m_view->setItemDelegateForColumn(LanguageClientSettingsModel::ExecutableColumn, executableDelegate);
auto buttonLayout = new QVBoxLayout();
auto addButton = new QPushButton(tr("&Add"));
connect(addButton, &QPushButton::pressed, this, &LanguageClientSettingsPageWidget::addItem);
auto deleteButton = new QPushButton(tr("&Delete"));
connect(deleteButton, &QPushButton::pressed, this, &LanguageClientSettingsPageWidget::deleteItem);
- setLayout(layout);
+ mainLayout->addLayout(layout);
+ setLayout(mainLayout);
layout->addWidget(m_view);
layout->addLayout(buttonLayout);
buttonLayout->addWidget(addButton);
@@ -185,6 +161,51 @@ LanguageClientSettingsPageWidget::LanguageClientSettingsPageWidget(LanguageClien
buttonLayout->addStretch(10);
}
+void LanguageClientSettingsPageWidget::currentChanged(const QModelIndex &index)
+{
+ if (m_currentSettings.widget) {
+ applyCurrentSettings();
+ layout()->removeWidget(m_currentSettings.widget);
+ delete m_currentSettings.widget;
+ }
+
+ if (index.isValid()) {
+ m_currentSettings.setting = m_settings.settingForIndex(index);
+ m_currentSettings.widget = m_currentSettings.setting->createSettingsWidget(this);
+ layout()->addWidget(m_currentSettings.widget);
+ } else {
+ m_currentSettings.setting = nullptr;
+ m_currentSettings.widget = nullptr;
+ }
+}
+
+int LanguageClientSettingsPageWidget::currentRow() const
+{
+ return m_settings.indexForSetting(m_currentSettings.setting).row();
+}
+
+void LanguageClientSettingsPageWidget::resetCurrentSettings(int row)
+{
+ if (m_currentSettings.widget) {
+ layout()->removeWidget(m_currentSettings.widget);
+ delete m_currentSettings.widget;
+ }
+
+ m_currentSettings.setting = nullptr;
+ m_currentSettings.widget = nullptr;
+ m_view->setCurrentIndex(m_settings.index(row));
+}
+
+void LanguageClientSettingsPageWidget::applyCurrentSettings()
+{
+ if (!m_currentSettings.setting)
+ return;
+
+ m_currentSettings.setting->applyFromSettingsWidget(m_currentSettings.widget);
+ auto index = m_settings.indexForSetting(m_currentSettings.setting);
+ m_settings.dataChanged(index, index);
+}
+
void LanguageClientSettingsPageWidget::addItem()
{
const int row = m_settings.rowCount();
@@ -233,6 +254,8 @@ QWidget *LanguageClientSettingsPage::widget()
void LanguageClientSettingsPage::apply()
{
qDeleteAll(m_settings);
+ if (m_widget)
+ m_widget->applyCurrentSettings();
m_settings = Utils::transform(m_model.settings(), [](const StdIOSettings *other){
return dynamic_cast<StdIOSettings *>(other->copy());
});
@@ -255,11 +278,19 @@ void LanguageClientSettingsPage::apply()
}
}
}
- m_model.reset(m_settings);
+
+ if (m_widget) {
+ int row = m_widget->currentRow();
+ m_model.reset(m_settings);
+ m_widget->resetCurrentSettings(row);
+ } else {
+ m_model.reset(m_settings);
+ }
}
void LanguageClientSettingsPage::finish()
{
+ m_model.reset(m_settings);
}
LanguageClientSettingsModel::~LanguageClientSettingsModel()
@@ -269,35 +300,13 @@ LanguageClientSettingsModel::~LanguageClientSettingsModel()
QVariant LanguageClientSettingsModel::data(const QModelIndex &index, int role) const
{
- if (!index.isValid())
+ StdIOSettings *setting = settingForIndex(index);
+ if (!setting)
return QVariant();
- StdIOSettings *setting = m_settings[index.row()];
- QTC_ASSERT(setting, return false);
- if (role == Qt::DisplayRole || role == Qt::EditRole) {
- switch (index.column()) {
- case DisplayNameColumn: return setting->m_name;
- case MimeTypeColumn: return setting->m_mimeType;
- case ExecutableColumn: return setting->m_executable;
- case ArgumentsColumn: return setting->m_arguments;
- }
- } else if (role == Qt::CheckStateRole && index.column() == EnabledColumn) {
+ if (role == Qt::DisplayRole)
+ return setting->m_name;
+ else if (role == Qt::CheckStateRole)
return setting->m_enabled ? Qt::Checked : Qt::Unchecked;
- }
- return QVariant();
-}
-
-QVariant LanguageClientSettingsModel::headerData(int section, Qt::Orientation orientation, int role) const
-{
- if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
- return QVariant();
-
- switch (section) {
- case DisplayNameColumn: return tr("Name");
- case EnabledColumn: return tr("Enabled");
- case MimeTypeColumn: return tr("Mime Type");
- case ExecutableColumn: return tr("Executable");
- case ArgumentsColumn: return tr("Arguments");
- }
return QVariant();
}
@@ -326,44 +335,20 @@ bool LanguageClientSettingsModel::insertRows(int row, int count, const QModelInd
bool LanguageClientSettingsModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
- if (!index.isValid())
+ StdIOSettings *setting = settingForIndex(index);
+ if (!setting || role != Qt::CheckStateRole)
return false;
- StdIOSettings *setting = m_settings[index.row()];
- QTC_ASSERT(setting, return false);
- if (role == Qt::DisplayRole || role == Qt::EditRole) {
- const QString strVal(value.toString());
- QString *settingsValue = nullptr;
- switch (index.column()) {
- case DisplayNameColumn: settingsValue = &setting->m_name; break;
- case MimeTypeColumn: settingsValue = &setting->m_mimeType; break;
- case ExecutableColumn: settingsValue = &setting->m_executable; break;
- case ArgumentsColumn: settingsValue = &setting->m_arguments; break;
- }
- if (settingsValue) {
- if (strVal != *settingsValue) {
- *settingsValue = value.toString();
- emit dataChanged(index, index, { Qt::EditRole, Qt::DisplayRole });
- }
- return true;
- }
- }
- if (role == Qt::CheckStateRole && index.column() == EnabledColumn) {
- if (setting->m_enabled != value.toBool()) {
- setting->m_enabled = !setting->m_enabled;
- emit dataChanged(index, index, { Qt::CheckStateRole });
- }
- return true;
+ if (setting->m_enabled != value.toBool()) {
+ setting->m_enabled = !setting->m_enabled;
+ emit dataChanged(index, index, { Qt::CheckStateRole });
}
- return false;
+ return true;
}
-Qt::ItemFlags LanguageClientSettingsModel::flags(const QModelIndex &index) const
+Qt::ItemFlags LanguageClientSettingsModel::flags(const QModelIndex &/*index*/) const
{
- const auto defaultFlags = Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
- if (index.column() == EnabledColumn)
- return defaultFlags | Qt::ItemIsUserCheckable;
- return defaultFlags;
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
}
void LanguageClientSettingsModel::reset(const QList<StdIOSettings *> &settings)
@@ -378,6 +363,32 @@ void LanguageClientSettingsModel::reset(const QList<StdIOSettings *> &settings)
endResetModel();
}
+StdIOSettings *LanguageClientSettingsModel::settingForIndex(const QModelIndex &index) const
+{
+ if (!index.isValid() || index.row() >= m_settings.size())
+ return nullptr;
+ return m_settings[index.row()];
+}
+
+QModelIndex LanguageClientSettingsModel::indexForSetting(StdIOSettings *setting) const
+{
+ const int index = m_settings.indexOf(setting);
+ return index < 0 ? QModelIndex() : createIndex(index, 0, setting);
+}
+
+void BaseSettings::applyFromSettingsWidget(QWidget *widget)
+{
+ if (auto settingsWidget = qobject_cast<BaseSettingsWidget *>(widget)) {
+ m_name = settingsWidget->name();
+ m_languageFilter = settingsWidget->filter();
+ }
+}
+
+QWidget *BaseSettings::createSettingsWidget(QWidget *parent) const
+{
+ return new BaseSettingsWidget(this, parent);
+}
+
bool BaseSettings::needsRestart() const
{
return m_client ? !m_enabled || m_client->needsRestart(this) : m_enabled;
@@ -398,7 +409,8 @@ QVariantMap BaseSettings::toMap() const
QVariantMap map;
map.insert(nameKey, m_name);
map.insert(enabledKey, m_enabled);
- map.insert(mimeTypeKey, m_mimeType);
+ map.insert(mimeTypeKey, m_languageFilter.mimeTypes);
+ map.insert(filePatternKey, m_languageFilter.filePattern);
return map;
}
@@ -406,7 +418,8 @@ void BaseSettings::fromMap(const QVariantMap &map)
{
m_name = map[nameKey].toString();
m_enabled = map[enabledKey].toBool();
- m_mimeType = map[mimeTypeKey].toString();
+ m_languageFilter.mimeTypes = map[mimeTypeKey].toStringList();
+ m_languageFilter.filePattern = map[filePatternKey].toStringList();
}
void LanguageClientSettings::init()
@@ -438,6 +451,20 @@ void LanguageClientSettings::toSettings(QSettings *settings, const QList<StdIOSe
settings->endGroup();
}
+void StdIOSettings::applyFromSettingsWidget(QWidget *widget)
+{
+ if (auto settingsWidget = qobject_cast<StdIOSettingsWidget *>(widget)) {
+ BaseSettings::applyFromSettingsWidget(settingsWidget);
+ m_executable = settingsWidget->executable();
+ m_arguments = settingsWidget->arguments();
+ }
+}
+
+QWidget *StdIOSettings::createSettingsWidget(QWidget *parent) const
+{
+ return new StdIOSettingsWidget(this, parent);
+}
+
bool StdIOSettings::needsRestart() const
{
if (BaseSettings::needsRestart())
@@ -456,8 +483,7 @@ BaseClient *StdIOSettings::createClient() const
{
auto client = new StdIOClient(m_executable, m_arguments);
client->setName(m_name);
- if (m_mimeType != noLanguageFilter)
- client->setSupportedMimeType({m_mimeType});
+ client->setSupportedLanguage(m_languageFilter);
return client;
}
@@ -476,4 +502,160 @@ void StdIOSettings::fromMap(const QVariantMap &map)
m_arguments = map[argumentsKey].toString();
}
+BaseSettingsWidget::BaseSettingsWidget(const BaseSettings *settings, QWidget *parent)
+ : QWidget(parent)
+ , m_name(new QLineEdit(settings->m_name, this))
+ , m_mimeTypes(new QLabel(settings->m_languageFilter.mimeTypes.join(filterSeparator), this))
+ , m_filePattern(new QLineEdit(settings->m_languageFilter.filePattern.join(filterSeparator), this))
+{
+ int row = 0;
+ auto *mainLayout = new QGridLayout;
+ mainLayout->addWidget(new QLabel(tr("Name:")), row, 0);
+ mainLayout->addWidget(m_name, row, 1);
+ mainLayout->addWidget(new QLabel(tr("Language:")), ++row, 0);
+ auto mimeLayout = new QHBoxLayout;
+ mimeLayout->addWidget(m_mimeTypes);
+ mimeLayout->addStretch();
+ auto addMimeTypeButton = new QPushButton(tr("Set MIME Types..."), this);
+ mimeLayout->addWidget(addMimeTypeButton);
+ mainLayout->addLayout(mimeLayout, row, 1);
+ m_filePattern->setPlaceholderText(tr("File pattern"));
+ mainLayout->addWidget(m_filePattern, ++row, 1);
+
+ connect(addMimeTypeButton, &QPushButton::pressed,
+ this, &BaseSettingsWidget::showAddMimeTypeDialog);
+
+ setLayout(mainLayout);
+}
+
+QString BaseSettingsWidget::name() const
+{
+ return m_name->text();
+}
+
+LanguageFilter BaseSettingsWidget::filter() const
+{
+ return {m_mimeTypes->text().split(filterSeparator),
+ m_filePattern->text().split(filterSeparator)};
+}
+
+class MimeTypeModel : public QStringListModel
+{
+public:
+ using QStringListModel::QStringListModel;
+ QVariant data(const QModelIndex &index, int role) const final
+ {
+ if (index.isValid() && role == Qt::CheckStateRole)
+ return m_selectedMimeTypes.contains(index.data().toString()) ? Qt::Checked : Qt::Unchecked;
+ return QStringListModel::data(index, role);
+ }
+ bool setData(const QModelIndex &index, const QVariant &value, int role) final
+ {
+ if (index.isValid() && role == Qt::CheckStateRole) {
+ QString mimeType = index.data().toString();
+ if (value.toInt() == Qt::Checked) {
+ if (!m_selectedMimeTypes.contains(mimeType))
+ m_selectedMimeTypes.append(index.data().toString());
+ } else {
+ m_selectedMimeTypes.removeAll(index.data().toString());
+ }
+ return true;
+ }
+ return QStringListModel::setData(index, value, role);
+ }
+
+ Qt::ItemFlags flags(const QModelIndex &index) const final
+ {
+ if (!index.isValid())
+ return Qt::NoItemFlags;
+ return (QStringListModel::flags(index)
+ & ~(Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled))
+ | Qt::ItemIsUserCheckable;
+ }
+ QStringList m_selectedMimeTypes;
+};
+
+class MimeTypeDialog : public QDialog
+{
+public:
+ explicit MimeTypeDialog(const QStringList &selectedMimeTypes, QWidget *parent = nullptr)
+ : QDialog(parent)
+ {
+ setWindowTitle(tr("Select MIME Types"));
+ auto mainLayout = new QVBoxLayout;
+ auto filter = new Utils::FancyLineEdit(this);
+ filter->setFiltering(true);
+ mainLayout->addWidget(filter);
+ auto listView = new QListView(this);
+ mainLayout->addWidget(listView);
+ auto buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
+ mainLayout->addWidget(buttons);
+ setLayout(mainLayout);
+
+ filter->setPlaceholderText(tr("Filter"));
+ connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
+ auto proxy = new QSortFilterProxyModel(this);
+ m_mimeTypeModel = new MimeTypeModel(Utils::transform(Utils::allMimeTypes(),
+ &Utils::MimeType::name), this);
+ m_mimeTypeModel->m_selectedMimeTypes = selectedMimeTypes;
+ proxy->setSourceModel(m_mimeTypeModel);
+ proxy->sort(0);
+ connect(filter, &QLineEdit::textChanged, proxy, &QSortFilterProxyModel::setFilterWildcard);
+ listView->setModel(proxy);
+
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setModal(true);
+ }
+
+ MimeTypeDialog(const MimeTypeDialog &other) = delete;
+ MimeTypeDialog(MimeTypeDialog &&other) = delete;
+
+ MimeTypeDialog operator=(const MimeTypeDialog &other) = delete;
+ MimeTypeDialog operator=(MimeTypeDialog &&other) = delete;
+
+
+ QStringList mimeTypes() const
+ {
+ return m_mimeTypeModel->m_selectedMimeTypes;
+ }
+private:
+ MimeTypeModel *m_mimeTypeModel = nullptr;
+};
+
+void BaseSettingsWidget::showAddMimeTypeDialog()
+{
+ MimeTypeDialog dialog(m_mimeTypes->text().split(filterSeparator, QString::SkipEmptyParts),
+ Core::ICore::dialogParent());
+ if (dialog.exec() == QDialog::Rejected)
+ return;
+ m_mimeTypes->setText(dialog.mimeTypes().join(filterSeparator));
+}
+
+StdIOSettingsWidget::StdIOSettingsWidget(const StdIOSettings *settings, QWidget *parent)
+ : BaseSettingsWidget(settings, parent)
+ , m_executable(new Utils::PathChooser(this))
+ , m_arguments(new QLineEdit(settings->m_arguments, this))
+{
+ auto mainLayout = qobject_cast<QGridLayout *>(layout());
+ QTC_ASSERT(mainLayout, return);
+ const int baseRows = mainLayout->rowCount();
+ mainLayout->addWidget(new QLabel(tr("Executable:")), baseRows, 0);
+ mainLayout->addWidget(m_executable, baseRows, 1);
+ mainLayout->addWidget(new QLabel(tr("Arguments:")), baseRows + 1, 0);
+ m_executable->setExpectedKind(Utils::PathChooser::ExistingCommand);
+ m_executable->setPath(QDir::toNativeSeparators(settings->m_executable));
+ mainLayout->addWidget(m_arguments, baseRows + 1, 1);
+}
+
+QString StdIOSettingsWidget::executable() const
+{
+ return m_executable->path();
+}
+
+QString StdIOSettingsWidget::arguments() const
+{
+ return m_arguments->text();
+}
+
} // namespace LanguageClient
diff --git a/src/plugins/languageclient/languageclientsettings.h b/src/plugins/languageclient/languageclientsettings.h
index 9f03d7d6ab..8068856ae2 100644
--- a/src/plugins/languageclient/languageclientsettings.h
+++ b/src/plugins/languageclient/languageclientsettings.h
@@ -28,32 +28,48 @@
#include <coreplugin/dialogs/ioptionspage.h>
#include <QAbstractItemModel>
+#include <QLabel>
#include <QPointer>
#include <QWidget>
+QT_BEGIN_NAMESPACE
+class QCheckBox;
+class QLineEdit;
+QT_END_NAMESPACE
+
+namespace Utils { class PathChooser; }
+
namespace LanguageClient {
constexpr char noLanguageFilter[] = "No Filter";
class BaseClient;
+struct LanguageFilter
+{
+ QStringList mimeTypes;
+ QStringList filePattern;
+};
+
class BaseSettings
{
public:
BaseSettings() = default;
- BaseSettings(const QString &name, bool enabled, const QString &mimeTypeName)
+ BaseSettings(const QString &name, bool enabled, const LanguageFilter &filter)
: m_name(name)
, m_enabled(enabled)
- , m_mimeType(mimeTypeName)
+ , m_languageFilter(filter)
{}
virtual ~BaseSettings() = default;
QString m_name = QString("New Language Server");
bool m_enabled = true;
- QString m_mimeType = QLatin1String(noLanguageFilter);
+ LanguageFilter m_languageFilter;
QPointer<BaseClient> m_client; // not owned
+ virtual void applyFromSettingsWidget(QWidget *widget);
+ virtual QWidget *createSettingsWidget(QWidget *parent = nullptr) const;
virtual BaseSettings *copy() const { return new BaseSettings(*this); }
virtual bool needsRestart() const;
virtual bool isValid() const ;
@@ -72,9 +88,9 @@ class StdIOSettings : public BaseSettings
{
public:
StdIOSettings() = default;
- StdIOSettings(const QString &name, bool enabled, const QString &mimeTypeName,
+ StdIOSettings(const QString &name, bool enabled, const LanguageFilter &filter,
const QString &executable, const QString &arguments)
- : BaseSettings(name, enabled, mimeTypeName)
+ : BaseSettings(name, enabled, filter)
, m_executable(executable)
, m_arguments(arguments)
{}
@@ -84,6 +100,8 @@ public:
QString m_executable;
QString m_arguments;
+ void applyFromSettingsWidget(QWidget *widget) override;
+ QWidget *createSettingsWidget(QWidget *parent = nullptr) const override;
BaseSettings *copy() const override { return new StdIOSettings(*this); }
bool needsRestart() const override;
bool isValid() const override;
@@ -106,4 +124,39 @@ public:
static void toSettings(QSettings *settings, const QList<StdIOSettings *> &languageClientSettings);
};
+class BaseSettingsWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit BaseSettingsWidget(const BaseSettings* settings, QWidget *parent = nullptr);
+ ~BaseSettingsWidget() = default;
+
+ QString name() const;
+ LanguageFilter filter() const;
+
+private:
+ void showAddMimeTypeDialog();
+
+ QLineEdit *m_name = nullptr;
+ QLabel *m_mimeTypes = nullptr;
+ QLineEdit *m_filePattern = nullptr;
+
+ static constexpr char filterSeparator = ';';
+};
+
+class StdIOSettingsWidget : public BaseSettingsWidget
+{
+ Q_OBJECT
+public:
+ explicit StdIOSettingsWidget(const StdIOSettings* settings, QWidget *parent = nullptr);
+ ~StdIOSettingsWidget() = default;
+
+ QString executable() const;
+ QString arguments() const;
+
+private:
+ Utils::PathChooser *m_executable = nullptr;
+ QLineEdit *m_arguments = nullptr;
+};
+
} // namespace LanguageClient
diff --git a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp
index 1c2b315095..cecf44be2c 100644
--- a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp
+++ b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp
@@ -278,11 +278,6 @@ QString CustomExecutableRunConfiguration::defaultDisplayName() const
return tr("Run %1").arg(QDir::toNativeSeparators(rawExecutable()));
}
-Abi CustomExecutableRunConfiguration::abi() const
-{
- return Abi(); // return an invalid ABI: We do not know what we will end up running!
-}
-
// Factory
CustomExecutableRunConfigurationFactory::CustomExecutableRunConfigurationFactory() :
diff --git a/src/plugins/projectexplorer/customexecutablerunconfiguration.h b/src/plugins/projectexplorer/customexecutablerunconfiguration.h
index c8b9d8144b..6abd0f3185 100644
--- a/src/plugins/projectexplorer/customexecutablerunconfiguration.h
+++ b/src/plugins/projectexplorer/customexecutablerunconfiguration.h
@@ -45,7 +45,6 @@ public:
/** Returns whether this runconfiguration ever was configured with an executable
*/
bool isConfigured() const override;
- Abi abi() const override;
ConfigurationState ensureConfigured(QString *errorMessage) override;
QString defaultDisplayName() const;
diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp
index 1af06a98ed..394d4a26ae 100644
--- a/src/plugins/projectexplorer/gcctoolchain.cpp
+++ b/src/plugins/projectexplorer/gcctoolchain.cpp
@@ -489,7 +489,7 @@ LanguageExtensions GccToolChain::languageExtensions(const QStringList &cxxflags)
else
extensions &= ~LanguageExtensions(LanguageExtension::Gnu);
} else if (flag == "-fopenmp") {
- extensions |= LanguageExtension::Gnu;
+ extensions |= LanguageExtension::OpenMP;
} else if (flag == "-fms-extensions") {
extensions |= LanguageExtension::Microsoft;
}
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
index c708dd5af4..894fadcfa4 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
@@ -31,6 +31,7 @@
#include "../project.h"
#include "../projectexplorer.h"
#include "../projectexplorerconstants.h"
+#include "../projecttree.h"
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/messagemanager.h>
@@ -290,7 +291,7 @@ void JsonWizard::accept()
openFiles(m_files);
auto node = static_cast<ProjectExplorer::Node*>(value(ProjectExplorer::Constants::PREFERRED_PROJECT_NODE).value<void*>());
- if (node) // PREFERRED_PROJECT_NODE is not set for newly created projects
+ if (node && ProjectTree::hasNode(node)) // PREFERRED_PROJECT_NODE is not set for newly created projects
openProjectForNode(node);
}
diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp
index 50c3a9d369..45fa8a5ece 100644
--- a/src/plugins/projectexplorer/msvctoolchain.cpp
+++ b/src/plugins/projectexplorer/msvctoolchain.cpp
@@ -1296,6 +1296,11 @@ bool MsvcToolChain::operator ==(const ToolChain &other) const
return m_varsBatArg == msvcTc->m_varsBatArg;
}
+void MsvcToolChain::cancelMsvcToolChainDetection()
+{
+ envModThreadPool()->clear();
+}
+
bool MsvcToolChainFactory::canRestore(const QVariantMap &data)
{
const Core::Id id = typeIdFromMap(data);
diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h
index 88ba1523cd..d26b8c52bf 100644
--- a/src/plugins/projectexplorer/msvctoolchain.h
+++ b/src/plugins/projectexplorer/msvctoolchain.h
@@ -82,6 +82,8 @@ public:
bool operator == (const ToolChain &) const override;
+ static void cancelMsvcToolChainDetection();
+
protected:
explicit MsvcToolChain(Core::Id typeId, const QString &name, const Abi &abi,
const QString &varsBat, const QString &varsBatArg,
diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp
index d8a131dc5f..5048c2d0ca 100644
--- a/src/plugins/projectexplorer/projectexplorer.cpp
+++ b/src/plugins/projectexplorer/projectexplorer.cpp
@@ -1739,6 +1739,7 @@ ExtensionSystem::IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown()
disconnect(ModeManager::instance(), &ModeManager::currentModeChanged,
dd, &ProjectExplorerPluginPrivate::currentModeChanged);
ProjectTree::aboutToShutDown();
+ ToolChainManager::aboutToShutdown();
SessionManager::closeAllProjects();
dd->m_shuttingDown = true;
diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp
index 9cf3167a24..08842aabea 100644
--- a/src/plugins/projectexplorer/projectwelcomepage.cpp
+++ b/src/plugins/projectexplorer/projectwelcomepage.cpp
@@ -127,12 +127,18 @@ ProjectWelcomePage::ProjectWelcomePage()
auto act = new QAction(tr("Open Session #%1").arg(i), this);
Command *cmd = ActionManager::registerAction(act, sessionBase.withSuffix(i), welcomeContext);
cmd->setDefaultKeySequence(QKeySequence((useMacShortcuts ? tr("Ctrl+Meta+%1") : tr("Ctrl+Alt+%1")).arg(i)));
- connect(act, &QAction::triggered, this, [this, i] { openSessionAt(i - 1); });
+ connect(act, &QAction::triggered, this, [this, i] {
+ if (i <= m_sessionModel->rowCount())
+ openSessionAt(i - 1);
+ });
act = new QAction(tr("Open Recent Project #%1").arg(i), this);
cmd = ActionManager::registerAction(act, projectBase.withSuffix(i), welcomeContext);
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+%1").arg(i)));
- connect(act, &QAction::triggered, this, [this, i] { openProjectAt(i - 1); });
+ connect(act, &QAction::triggered, this, [this, i] {
+ if (i <= m_projectModel->rowCount(QModelIndex()))
+ openProjectAt(i - 1);
+ });
}
}
diff --git a/src/plugins/projectexplorer/projectwizardpage.cpp b/src/plugins/projectexplorer/projectwizardpage.cpp
index ee86abe895..500a13a4fc 100644
--- a/src/plugins/projectexplorer/projectwizardpage.cpp
+++ b/src/plugins/projectexplorer/projectwizardpage.cpp
@@ -456,10 +456,11 @@ void ProjectWizardPage::initializeProjectTree(Node *context, const QStringList &
}
root->prependChild(createNoneNode(&selector));
- // Set combobox to context node:
+ // Set combobox to context node if that appears in the tree:
auto predicate = [context](TreeItem *ti) { return static_cast<AddNewTree*>(ti)->node() == context; };
TreeItem *contextItem = root->findAnyChild(predicate);
- m_ui->projectComboBox->setCurrentIndex(m_model.indexForItem(contextItem));
+ if (contextItem)
+ m_ui->projectComboBox->setCurrentIndex(m_model.indexForItem(contextItem));
setAdditionalInfo(selector.deployingProjects());
setBestNode(selector.bestChoice());
diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp
index e6f0302bdf..d5ec08471f 100644
--- a/src/plugins/projectexplorer/runconfiguration.cpp
+++ b/src/plugins/projectexplorer/runconfiguration.cpp
@@ -310,17 +310,6 @@ QVariantMap RunConfiguration::toMap() const
return map;
}
-Abi RunConfiguration::abi() const
-{
- BuildConfiguration *bc = target()->activeBuildConfiguration();
- if (!bc)
- return Abi::hostAbi();
- ToolChain *tc = ToolChainKitInformation::toolChain(target()->kit(), Constants::CXX_LANGUAGE_ID);
- if (!tc)
- return Abi::hostAbi();
- return tc->targetAbi();
-}
-
BuildTargetInfo RunConfiguration::buildTargetInfo() const
{
return target()->applicationTargets().buildTargetInfo(m_buildKey);
@@ -1334,13 +1323,6 @@ Utils::Icon RunControl::icon() const
return d->icon;
}
-Abi RunControl::abi() const
-{
- if (const RunConfiguration *rc = d->runConfiguration.data())
- return rc->abi();
- return Abi();
-}
-
IDevice::ConstPtr RunControl::device() const
{
return d->device;
diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h
index 9a973b42eb..c31aeb9de0 100644
--- a/src/plugins/projectexplorer/runconfiguration.h
+++ b/src/plugins/projectexplorer/runconfiguration.h
@@ -46,7 +46,6 @@
namespace Utils { class OutputFormatter; }
namespace ProjectExplorer {
-class Abi;
class BuildConfiguration;
class GlobalOrProjectAspect;
class Node;
@@ -172,7 +171,6 @@ public:
QVariantMap toMap() const override;
virtual Runnable runnable() const;
- virtual Abi abi() const;
// Return a handle to the build system target that created this run configuration.
// May return an empty string if no target built the executable!
@@ -439,7 +437,6 @@ public:
Utils::ProcessHandle applicationProcessHandle() const;
void setApplicationProcessHandle(const Utils::ProcessHandle &handle);
- Abi abi() const;
IDevice::ConstPtr device() const;
RunConfiguration *runConfiguration() const;
diff --git a/src/plugins/projectexplorer/toolchainmanager.cpp b/src/plugins/projectexplorer/toolchainmanager.cpp
index 2a5c899570..caa15e6d2f 100644
--- a/src/plugins/projectexplorer/toolchainmanager.cpp
+++ b/src/plugins/projectexplorer/toolchainmanager.cpp
@@ -27,6 +27,7 @@
#include "abi.h"
#include "kitinformation.h"
+#include "msvctoolchain.h"
#include "toolchain.h"
#include "toolchainsettingsaccessor.h"
@@ -249,4 +250,11 @@ bool ToolChainManager::isLanguageSupported(const Core::Id &id)
return Utils::contains(d->m_languages, Utils::equal(&LanguageDisplayPair::id, id));
}
+void ToolChainManager::aboutToShutdown()
+{
+#ifdef Q_OS_WIN
+ MsvcToolChain::cancelMsvcToolChainDetection();
+#endif
+}
+
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/toolchainmanager.h b/src/plugins/projectexplorer/toolchainmanager.h
index 3fdcd98126..2e26431b84 100644
--- a/src/plugins/projectexplorer/toolchainmanager.h
+++ b/src/plugins/projectexplorer/toolchainmanager.h
@@ -74,6 +74,8 @@ public:
static QString displayNameOfLanguageId(const Core::Id &id);
static bool isLanguageSupported(const Core::Id &id);
+ static void aboutToShutdown();
+
void saveToolChains();
signals:
diff --git a/src/plugins/projectexplorer/windebuginterface.cpp b/src/plugins/projectexplorer/windebuginterface.cpp
index ce3950acb9..2f7bbcc4d8 100644
--- a/src/plugins/projectexplorer/windebuginterface.cpp
+++ b/src/plugins/projectexplorer/windebuginterface.cpp
@@ -177,6 +177,8 @@ void WinDebugInterface::dispatchDebugOutput()
m_outputMutex.lock();
for (auto &entry : m_debugOutput) {
std::vector<QString> &src = entry.second;
+ if (src.empty())
+ continue;
QString dst;
size_t n = std::min(maxMessagesToSend, src.size());
for (size_t i = 0; i < n; ++i)
diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp
index 7981547ab3..a1df7d2e2c 100644
--- a/src/plugins/qbsprojectmanager/qbsproject.cpp
+++ b/src/plugins/qbsprojectmanager/qbsproject.cpp
@@ -72,6 +72,7 @@
#include <QElapsedTimer>
#include <QFileInfo>
#include <QMessageBox>
+#include <QSet>
#include <QVariantMap>
#include <algorithm>
@@ -936,13 +937,14 @@ void QbsProject::updateCppCodeModel()
QString objcPch;
QString objcxxPch;
const auto &pchFinder = [&cPch, &cxxPch, &objcPch, &objcxxPch](const qbs::ArtifactData &a) {
- if (a.fileTags().contains("c_pch_src"))
+ const QStringList fileTags = a.fileTags();
+ if (fileTags.contains("c_pch_src"))
cPch = a.filePath();
- else if (a.fileTags().contains("cpp_pch_src"))
+ if (fileTags.contains("cpp_pch_src"))
cxxPch = a.filePath();
- else if (a.fileTags().contains("objc_pch_src"))
+ if (fileTags.contains("objc_pch_src"))
objcPch = a.filePath();
- else if (a.fileTags().contains("objcpp_pch_src"))
+ if (fileTags.contains("objcpp_pch_src"))
objcxxPch = a.filePath();
};
const QList<qbs::ArtifactData> &generatedArtifacts = prd.generatedArtifacts();
@@ -1038,7 +1040,7 @@ void QbsProject::updateCppCodeModel()
}
}
- QStringList pchFiles;
+ QSet<QString> pchFiles;
if (hasCFiles && props.getModuleProperty("cpp", "useCPrecompiledHeader").toBool()
&& !cPch.isEmpty()) {
pchFiles << cPch;
@@ -1061,7 +1063,7 @@ void QbsProject::updateCppCodeModel()
<< grp.name() << "in product" << prd.name();
qCWarning(qbsPmLog) << "Expect problems with code model";
}
- rpp.setPreCompiledHeaders(pchFiles);
+ rpp.setPreCompiledHeaders(pchFiles.toList());
rpp.setFiles(grp.allFilePaths(), [filePathToSourceArtifact](const QString &filePath) {
// Keep this lambda thread-safe!
return cppFileType(filePathToSourceArtifact.value(filePath));
diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp
index 0dce2b2a10..43cc0f5f24 100644
--- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp
+++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp
@@ -371,7 +371,11 @@ QString PuppetCreator::qmlPuppetDirectory(PuppetType puppetType) const
return qmlPuppetToplevelBuildDirectory() + '/' + QCoreApplication::applicationVersion()
+ '/' + QString::fromLatin1(qtHash());
- return qmlPuppetFallbackDirectory();
+#ifndef QMLDESIGNER_TEST
+ return qmlPuppetFallbackDirectory(m_designerSettings);
+#else
+ return QString();
+#endif
}
QString PuppetCreator::defaultPuppetFallbackDirectory()
@@ -382,15 +386,16 @@ QString PuppetCreator::defaultPuppetFallbackDirectory()
return Core::ICore::libexecPath();
}
-QString PuppetCreator::qmlPuppetFallbackDirectory() const
+QString PuppetCreator::qmlPuppetFallbackDirectory(const DesignerSettings &settings)
{
#ifndef QMLDESIGNER_TEST
- QString puppetFallbackDirectory = m_designerSettings.value(
+ QString puppetFallbackDirectory = settings.value(
DesignerSettingsKey::PUPPET_FALLBACK_DIRECTORY).toString();
- if (puppetFallbackDirectory.isEmpty())
+ if (puppetFallbackDirectory.isEmpty() || !QFileInfo::exists(puppetFallbackDirectory))
return defaultPuppetFallbackDirectory();
return puppetFallbackDirectory;
#else
+ Q_UNUSED(settings);
return QString();
#endif
}
diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.h b/src/plugins/qmldesigner/designercore/instances/puppetcreator.h
index 95c7d7e68a..8cde9692ad 100644
--- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.h
+++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.h
@@ -66,12 +66,12 @@ public:
static QString defaultPuppetToplevelBuildDirectory();
static QString defaultPuppetFallbackDirectory();
+ static QString qmlPuppetFallbackDirectory(const DesignerSettings &settings);
protected:
bool build(const QString &qmlPuppetProjectFilePath) const;
QString qmlPuppetToplevelBuildDirectory() const;
- QString qmlPuppetFallbackDirectory() const;
QString qmlPuppetDirectory(PuppetType puppetPathType) const;
QString qml2PuppetPath(PuppetType puppetType) const;
diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp
index 6fb88e5f21..041efd809b 100644
--- a/src/plugins/qmldesigner/settingspage.cpp
+++ b/src/plugins/qmldesigner/settingspage.cpp
@@ -69,7 +69,6 @@ SettingsPageWidget::SettingsPageWidget(QWidget *parent) :
PuppetCreator::defaultPuppetFallbackDirectory());
}
);
- m_ui.fallbackPuppetPathLineEdit->setPath(PuppetCreator::defaultPuppetFallbackDirectory());
m_ui.fallbackPuppetPathLineEdit->lineEdit()->setPlaceholderText(PuppetCreator::defaultPuppetFallbackDirectory());
connect(m_ui.resetQmlPuppetBuildPathButton, &QPushButton::clicked, [=]() {
@@ -138,11 +137,15 @@ DesignerSettings SettingsPageWidget::settings() const
m_ui.fallbackPuppetPathLineEdit->lineEdit()->placeholderText());
if (newFallbackPuppetPath.isEmpty())
newFallbackPuppetPath = m_ui.fallbackPuppetPathLineEdit->lineEdit()->placeholderText();
- QString oldFallbackPuppetPath = settings.value(DesignerSettingsKey::PUPPET_FALLBACK_DIRECTORY,
- PuppetCreator::defaultPuppetFallbackDirectory()).toString();
- if (oldFallbackPuppetPath != newFallbackPuppetPath) {
- settings.insert(DesignerSettingsKey::PUPPET_FALLBACK_DIRECTORY,
- newFallbackPuppetPath);
+ QString oldFallbackPuppetPath = PuppetCreator::qmlPuppetFallbackDirectory(settings);
+
+ if (oldFallbackPuppetPath != newFallbackPuppetPath && QFileInfo::exists(newFallbackPuppetPath)) {
+ if (newFallbackPuppetPath == PuppetCreator::defaultPuppetFallbackDirectory())
+ settings.insert(DesignerSettingsKey::PUPPET_FALLBACK_DIRECTORY, QString());
+ else
+ settings.insert(DesignerSettingsKey::PUPPET_FALLBACK_DIRECTORY, newFallbackPuppetPath);
+ } else if (!QFileInfo::exists(oldFallbackPuppetPath) || !QFileInfo::exists(newFallbackPuppetPath)){
+ settings.insert(DesignerSettingsKey::PUPPET_FALLBACK_DIRECTORY, QString());
}
if (!m_ui.puppetBuildPathLineEdit->path().isEmpty() &&
diff --git a/src/plugins/qmlprofiler/tests/qmlprofilertool_test.cpp b/src/plugins/qmlprofiler/tests/qmlprofilertool_test.cpp
index a519f6a775..8f7ecb778e 100644
--- a/src/plugins/qmlprofiler/tests/qmlprofilertool_test.cpp
+++ b/src/plugins/qmlprofiler/tests/qmlprofilertool_test.cpp
@@ -54,6 +54,13 @@ void QmlProfilerToolTest::testAttachToWaitingApplication()
settings->setValue(QLatin1String("AnalyzerQmlAttachDialog/kitId"), newKitPtr->id().toSetting());
QmlProfilerTool profilerTool;
+
+ QmlProfilerClientManager *clientManager = profilerTool.clientManager();
+ clientManager->setRetryInterval(10);
+ clientManager->setMaximumRetries(10);
+ connect(clientManager, &QmlProfilerClientManager::connectionFailed,
+ clientManager, &QmlProfilerClientManager::retryConnect);
+
QTcpServer server;
QUrl serverUrl = Utils::urlFromLocalHostAndFreePort();
QVERIFY(serverUrl.port() >= 0);
@@ -64,7 +71,6 @@ void QmlProfilerToolTest::testAttachToWaitingApplication()
connect(&server, &QTcpServer::newConnection, this, [&]() {
connection.reset(server.nextPendingConnection());
fakeDebugServer(connection.data());
- server.close();
});
QTimer timer;
@@ -94,7 +100,7 @@ void QmlProfilerToolTest::testAttachToWaitingApplication()
QTRY_VERIFY(runControl->isRunning());
QTRY_VERIFY(modalSeen);
QTRY_VERIFY(!timer.isActive());
- QTRY_VERIFY(profilerTool.clientManager()->isConnected());
+ QTRY_VERIFY(clientManager->isConnected());
connection.reset();
QTRY_VERIFY(runControl->isStopped());
diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp
index 55e32ec508..9ba68b556a 100644
--- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp
+++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp
@@ -374,13 +374,6 @@ QString QmlProjectRunConfiguration::commandLineArguments() const
return args;
}
-Abi QmlProjectRunConfiguration::abi() const
-{
- Abi hostAbi = Abi::hostAbi();
- return Abi(hostAbi.architecture(), hostAbi.os(), hostAbi.osFlavor(),
- Abi::RuntimeQmlFormat, hostAbi.wordWidth());
-}
-
void QmlProjectRunConfiguration::updateEnabledState()
{
bool qmlFileFound = m_mainQmlFileAspect->isQmlFilePresent();
diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.h b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.h
index b67e4238f0..adfd3103a7 100644
--- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.h
+++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.h
@@ -44,7 +44,6 @@ public:
private:
ProjectExplorer::Runnable runnable() const final;
QString disabledReason() const final;
- ProjectExplorer::Abi abi() const final;
void updateEnabledState() final;
QString mainScript() const;
diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp
index 2a01ada15c..15c7f56cc8 100644
--- a/src/plugins/texteditor/codeassist/codeassistant.cpp
+++ b/src/plugins/texteditor/codeassist/codeassistant.cpp
@@ -245,10 +245,17 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason,
case IAssistProvider::Asynchronous: {
processor->setAsyncCompletionAvailableHandler(
[this, reason](IAssistProposal *newProposal){
- invalidateCurrentRequestData();
- displayProposal(newProposal, reason);
-
- emit q->finished();
+ if (m_asyncProcessor && m_asyncProcessor->needsRestart() && m_receivedContentWhileWaiting) {
+ delete newProposal;
+ m_receivedContentWhileWaiting = false;
+ invalidateCurrentRequestData();
+ requestProposal(reason, m_assistKind, m_requestProvider);
+ } else {
+ invalidateCurrentRequestData();
+ displayProposal(newProposal, reason);
+
+ emit q->finished();
+ }
});
// If there is a proposal, nothing asynchronous happened...
diff --git a/src/plugins/texteditor/codeassist/iassistprocessor.h b/src/plugins/texteditor/codeassist/iassistprocessor.h
index 23c06b6835..6ed29b66f1 100644
--- a/src/plugins/texteditor/codeassist/iassistprocessor.h
+++ b/src/plugins/texteditor/codeassist/iassistprocessor.h
@@ -50,6 +50,7 @@ public:
void setAsyncCompletionAvailableHandler(const AsyncCompletionsAvailableHandler &finalizer);
virtual bool running() { return false; }
+ virtual bool needsRestart() const { return false; }
private:
AsyncCompletionsAvailableHandler m_asyncCompletionsAvailableHandler;
diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp
index 89823a7c12..3141a12620 100644
--- a/src/plugins/texteditor/texteditor.cpp
+++ b/src/plugins/texteditor/texteditor.cpp
@@ -2474,6 +2474,7 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
e->accept();
if (extraBlocks > 0) {
+ cursor.joinPreviousEditBlock();
const int cursorPosition = cursor.position();
QTextCursor ensureVisible = cursor;
while (extraBlocks > 0) {
@@ -2493,6 +2494,7 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
}
setTextCursor(ensureVisible);
cursor.setPosition(cursorPosition);
+ cursor.endEditBlock();
}
setTextCursor(cursor);
diff --git a/src/plugins/vcsbase/vcscommand.cpp b/src/plugins/vcsbase/vcscommand.cpp
index af1eac8f32..5433455981 100644
--- a/src/plugins/vcsbase/vcscommand.cpp
+++ b/src/plugins/vcsbase/vcscommand.cpp
@@ -29,6 +29,7 @@
#include <coreplugin/documentmanager.h>
#include <coreplugin/vcsmanager.h>
+#include <cpptools/cppmodelmanager.h>
#include <utils/synchronousprocess.h>
#include <QProcessEnvironment>
@@ -42,7 +43,7 @@ VcsCommand::VcsCommand(const QString &workingDirectory,
Core::ShellCommand(workingDirectory, environment),
m_preventRepositoryChanged(false)
{
- setOutputProxyFactory([this]() -> OutputProxy * {
+ setOutputProxyFactory([this] {
auto proxy = new OutputProxy;
VcsOutputWindow *outputWindow = VcsOutputWindow::instance();
@@ -60,12 +61,16 @@ VcsCommand::VcsCommand(const QString &workingDirectory,
return proxy;
});
connect(this, &VcsCommand::started, this, [this] {
- if (flags() & ExpectRepoChanges)
+ if (flags() & ExpectRepoChanges) {
Core::DocumentManager::setAutoReloadPostponed(true);
+ CppTools::CppModelManager::instance()->setBackendJobsPostponed(true);
+ }
});
connect(this, &VcsCommand::finished, this, [this] {
- if (flags() & ExpectRepoChanges)
+ if (flags() & ExpectRepoChanges) {
Core::DocumentManager::setAutoReloadPostponed(false);
+ CppTools::CppModelManager::instance()->setBackendJobsPostponed(false);
+ }
});
}
diff --git a/src/shared/qbs b/src/shared/qbs
-Subproject fa5e42f915211637da0d6461c9764962ee47f92
+Subproject b9e5dd581a06a97d45260fa9b393b135a9f1ad8
diff --git a/src/tools/clangbackend/source/clangfollowsymbol.cpp b/src/tools/clangbackend/source/clangfollowsymbol.cpp
index f8d763ae5e..27e8fb61e9 100644
--- a/src/tools/clangbackend/source/clangfollowsymbol.cpp
+++ b/src/tools/clangbackend/source/clangfollowsymbol.cpp
@@ -112,7 +112,7 @@ FollowSymbolResult FollowSymbol::followSymbol(CXTranslationUnit tu,
if (cursor.kind() == CXCursor_InclusionDirective) {
CXFile file = clang_getIncludedFile(cursors[tokenIndex].cx());
const ClangString filename(clang_getFileName(file));
- const SourceLocation loc(tu, filename, 1, 1);
+ const SourceLocation loc(tu, clang_getLocation(tu, file, 1, 1));
FollowSymbolResult result;
result.range = SourceRangeContainer(SourceRange(loc, loc));
// CLANG-UPGRADE-CHECK: Remove if we don't use empty generated ui_* headers anymore.
diff --git a/src/tools/clangbackend/source/clangtranslationunit.cpp b/src/tools/clangbackend/source/clangtranslationunit.cpp
index 6eebc8e203..cc848f89ab 100644
--- a/src/tools/clangbackend/source/clangtranslationunit.cpp
+++ b/src/tools/clangbackend/source/clangtranslationunit.cpp
@@ -154,14 +154,22 @@ DiagnosticSet TranslationUnit::diagnostics() const
SourceLocation TranslationUnit::sourceLocationAt(uint line,uint column) const
{
- return SourceLocation(m_cxTranslationUnit, m_filePath, line, column);
+ return SourceLocation(m_cxTranslationUnit,
+ clang_getLocation(m_cxTranslationUnit,
+ clang_getFile(m_cxTranslationUnit,
+ m_filePath.constData()),
+ line, column));
}
SourceLocation TranslationUnit::sourceLocationAt(const Utf8String &filePath,
uint line,
uint column) const
{
- return SourceLocation(m_cxTranslationUnit, filePath, line, column);
+ return SourceLocation(m_cxTranslationUnit,
+ clang_getLocation(m_cxTranslationUnit,
+ clang_getFile(m_cxTranslationUnit,
+ filePath.constData()),
+ line, column));
}
SourceRange TranslationUnit::sourceRange(uint fromLine,
diff --git a/src/tools/clangbackend/source/codecompleter.cpp b/src/tools/clangbackend/source/codecompleter.cpp
index 5520b5b3a9..0613adf146 100644
--- a/src/tools/clangbackend/source/codecompleter.cpp
+++ b/src/tools/clangbackend/source/codecompleter.cpp
@@ -48,14 +48,14 @@ namespace ClangBackEnd {
namespace {
-CodeCompletions toCodeCompletions(const TranslationUnit &translationUnit,
+CodeCompletions toCodeCompletions(const UnsavedFile &unsavedFile,
const ClangCodeCompleteResults &results,
bool onlyFunctionOverloads)
{
if (results.isNull())
return CodeCompletions();
- CodeCompletionsExtractor extractor(translationUnit.cxTranslationUnit(), results.data());
+ CodeCompletionsExtractor extractor(unsavedFile, results.data());
CodeCompletions codeCompletions = extractor.extractAll(onlyFunctionOverloads);
return codeCompletions;
@@ -118,7 +118,9 @@ CodeCompletions CodeCompleter::complete(uint line, uint column,
filterUnknownContextResults(clangCompletions, unsavedFile(), line, column);
- return toCodeCompletions(translationUnit, clangCompletions, funcNameStartLine >= 0);
+ return toCodeCompletions(unsavedFiles.unsavedFile(translationUnit.filePath()),
+ clangCompletions,
+ funcNameStartLine >= 0);
}
// For given "make_unique<T>" / "make_shared<T>" / "QSharedPointer<T>::create" return "new T("
diff --git a/src/tools/clangbackend/source/codecompletionsextractor.cpp b/src/tools/clangbackend/source/codecompletionsextractor.cpp
index 25be6bddcf..2e2817c72b 100644
--- a/src/tools/clangbackend/source/codecompletionsextractor.cpp
+++ b/src/tools/clangbackend/source/codecompletionsextractor.cpp
@@ -31,19 +31,20 @@
#include "codecompletionchunkconverter.h"
#include "sourcelocation.h"
#include "sourcerange.h"
+#include "unsavedfile.h"
#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
#include <QDebug>
namespace ClangBackEnd {
-CodeCompletionsExtractor::CodeCompletionsExtractor(CXTranslationUnit cxTranslationUnit,
+CodeCompletionsExtractor::CodeCompletionsExtractor(const UnsavedFile &unsavedFile,
CXCodeCompleteResults *cxCodeCompleteResults)
- : cxTranslationUnit(cxTranslationUnit)
+ : unsavedFile(unsavedFile)
, cxCodeCompleteResults(cxCodeCompleteResults)
{
-
}
bool CodeCompletionsExtractor::next()
@@ -342,6 +343,27 @@ void CodeCompletionsExtractor::extractCompletionChunks()
currentCodeCompletion_.chunks = CodeCompletionChunkConverter::extract(currentCxCodeCompleteResult.CompletionString);
}
+SourceRangeContainer toRangeContainer(const UnsavedFile &file, CXSourceRange cxSourceRange)
+{
+ const CXSourceLocation start = clang_getRangeStart(cxSourceRange);
+ const CXSourceLocation end = clang_getRangeEnd(cxSourceRange);
+
+ uint startLine = 0;
+ uint startColumn = 0;
+ uint endLine = 0;
+ uint endColumn = 0;
+ clang_getFileLocation(start, nullptr, &startLine, &startColumn, nullptr);
+ clang_getFileLocation(end, nullptr, &endLine, &endColumn, nullptr);
+ QTC_ASSERT(startLine == endLine, return SourceRangeContainer(););
+
+ const Utf8String lineText = file.lineRange(startLine, endLine);
+ startColumn = QString(lineText.mid(0, startColumn - 1)).size() + 1;
+ endColumn = QString(lineText.mid(0, endColumn - 1)).size() + 1;
+
+ return SourceRangeContainer(SourceLocationContainer(file.filePath(), startLine, startColumn),
+ SourceLocationContainer(file.filePath(), endLine, endColumn));
+}
+
void CodeCompletionsExtractor::extractRequiredFixIts()
{
#ifdef IS_COMPLETION_FIXITS_BACKPORTED
@@ -358,7 +380,7 @@ void CodeCompletionsExtractor::extractRequiredFixIts()
i,
&range);
currentCodeCompletion_.requiredFixIts.push_back(
- FixItContainer(Utf8String(fixIt), SourceRange(cxTranslationUnit, range)));
+ FixItContainer(Utf8String(fixIt), toRangeContainer(unsavedFile, range)));
}
#endif
}
diff --git a/src/tools/clangbackend/source/codecompletionsextractor.h b/src/tools/clangbackend/source/codecompletionsextractor.h
index 928dabd25d..bba9aa6eb5 100644
--- a/src/tools/clangbackend/source/codecompletionsextractor.h
+++ b/src/tools/clangbackend/source/codecompletionsextractor.h
@@ -35,10 +35,12 @@
namespace ClangBackEnd {
+class UnsavedFile;
+
class CodeCompletionsExtractor
{
public:
- CodeCompletionsExtractor(CXTranslationUnit cxTranslationUnit,
+ CodeCompletionsExtractor(const UnsavedFile &unsavedFile,
CXCodeCompleteResults *cxCodeCompleteResults);
CodeCompletionsExtractor(CodeCompletionsExtractor&) = delete;
@@ -79,7 +81,7 @@ private:
private:
CodeCompletion currentCodeCompletion_;
- CXTranslationUnit cxTranslationUnit;
+ const UnsavedFile &unsavedFile;
CXCompletionResult currentCxCodeCompleteResult;
CXCodeCompleteResults *cxCodeCompleteResults;
uint cxCodeCompleteResultIndex = 0;
diff --git a/src/tools/clangbackend/source/skippedsourceranges.cpp b/src/tools/clangbackend/source/skippedsourceranges.cpp
index f15bd44668..2ce2f15acb 100644
--- a/src/tools/clangbackend/source/skippedsourceranges.cpp
+++ b/src/tools/clangbackend/source/skippedsourceranges.cpp
@@ -66,7 +66,11 @@ static SourceRange adaptedSourceRange(CXTranslationUnit cxTranslationUnit, const
return SourceRange {
range.start(),
- SourceLocation(cxTranslationUnit, end.filePath(), end.line(), 1)
+ SourceLocation(cxTranslationUnit,
+ clang_getLocation(cxTranslationUnit,
+ clang_getFile(cxTranslationUnit,
+ end.filePath().constData()),
+ end.line(), 1))
};
}
diff --git a/src/tools/clangbackend/source/sourcelocation.cpp b/src/tools/clangbackend/source/sourcelocation.cpp
index 7fbe8c03eb..70bb0e16aa 100644
--- a/src/tools/clangbackend/source/sourcelocation.cpp
+++ b/src/tools/clangbackend/source/sourcelocation.cpp
@@ -40,93 +40,92 @@
namespace ClangBackEnd {
SourceLocation::SourceLocation()
- : cxSourceLocation(clang_getNullLocation())
+ : m_cxSourceLocation(clang_getNullLocation())
{
}
const Utf8String &SourceLocation::filePath() const
{
- if (isFilePathNormalized_)
- return filePath_;
+ if (!m_isEvaluated)
+ evaluate();
- isFilePathNormalized_ = true;
- filePath_ = FilePath::fromNativeSeparators(filePath_);
+ if (m_isFilePathNormalized)
+ return m_filePath;
- return filePath_;
+ m_isFilePathNormalized = true;
+ m_filePath = FilePath::fromNativeSeparators(m_filePath);
+
+ return m_filePath;
}
uint SourceLocation::line() const
{
- return line_;
+ if (!m_isEvaluated)
+ evaluate();
+ return m_line;
}
uint SourceLocation::column() const
{
- return column_;
+ if (!m_isEvaluated)
+ evaluate();
+ return m_column;
}
uint SourceLocation::offset() const
{
- return offset_;
+ if (!m_isEvaluated)
+ evaluate();
+ return m_offset;
}
SourceLocationContainer SourceLocation::toSourceLocationContainer() const
{
- return SourceLocationContainer(filePath(), line_, column_);
+ if (!m_isEvaluated)
+ evaluate();
+ return SourceLocationContainer(filePath(), m_line, m_column);
}
-SourceLocation::SourceLocation(CXTranslationUnit cxTranslationUnit,
- CXSourceLocation cxSourceLocation)
- : cxSourceLocation(cxSourceLocation)
- , cxTranslationUnit(cxTranslationUnit)
+void SourceLocation::evaluate() const
{
+ m_isEvaluated = true;
+
CXFile cxFile;
- clang_getFileLocation(cxSourceLocation,
+ clang_getFileLocation(m_cxSourceLocation,
&cxFile,
- &line_,
- &column_,
- &offset_);
+ &m_line,
+ &m_column,
+ &m_offset);
- isFilePathNormalized_ = false;
+ m_isFilePathNormalized = false;
if (!cxFile)
return;
- filePath_ = ClangString(clang_getFileName(cxFile));
- if (column_ > 1) {
- const uint lineStart = offset_ + 1 - column_;
- const char *contents = clang_getFileContents(cxTranslationUnit, cxFile, nullptr);
+ m_filePath = ClangString(clang_getFileName(cxFile));
+ if (m_column > 1) {
+ const uint lineStart = m_offset + 1 - m_column;
+ const char *contents = clang_getFileContents(m_cxTranslationUnit, cxFile, nullptr);
if (!contents)
return;
// (1) column in SourceLocation is the actual column shown by CppEditor.
// (2) column in Clang is the utf8 byte offset from the beginning of the line.
// Here we convert column from (2) to (1).
- column_ = static_cast<uint>(QString::fromUtf8(&contents[lineStart],
- static_cast<int>(column_)).size());
+ m_column = static_cast<uint>(QString::fromUtf8(&contents[lineStart],
+ static_cast<int>(m_column) - 1).size()) + 1;
}
}
SourceLocation::SourceLocation(CXTranslationUnit cxTranslationUnit,
- const Utf8String &filePath,
- uint line,
- uint column)
- : cxSourceLocation(clang_getLocation(cxTranslationUnit,
- clang_getFile(cxTranslationUnit,
- filePath.constData()),
- line,
- column)),
- cxTranslationUnit(cxTranslationUnit),
- filePath_(filePath),
- line_(line),
- column_(column),
- isFilePathNormalized_(true)
+ CXSourceLocation cxSourceLocation)
+ : m_cxSourceLocation(cxSourceLocation)
+ , m_cxTranslationUnit(cxTranslationUnit)
{
- clang_getFileLocation(cxSourceLocation, 0, 0, 0, &offset_);
}
SourceLocation::operator CXSourceLocation() const
{
- return cxSourceLocation;
+ return m_cxSourceLocation;
}
std::ostream &operator<<(std::ostream &os, const SourceLocation &sourceLocation)
diff --git a/src/tools/clangbackend/source/sourcelocation.h b/src/tools/clangbackend/source/sourcelocation.h
index da0e68f973..63a600a2a6 100644
--- a/src/tools/clangbackend/source/sourcelocation.h
+++ b/src/tools/clangbackend/source/sourcelocation.h
@@ -41,7 +41,7 @@ class SourceLocation
friend bool operator==(const SourceLocation &first, const SourceLocation &second)
{
- return clang_equalLocations(first.cxSourceLocation, second.cxSourceLocation);
+ return clang_equalLocations(first.m_cxSourceLocation, second.m_cxSourceLocation);
}
friend bool operator!=(const SourceLocation &first, const SourceLocation &second)
{
@@ -51,10 +51,6 @@ class SourceLocation
public:
SourceLocation();
SourceLocation(CXTranslationUnit cxTranslationUnit,
- const Utf8String &filePath,
- uint line,
- uint column);
- SourceLocation(CXTranslationUnit cxTranslationUnit,
CXSourceLocation cxSourceLocation);
const Utf8String &filePath() const;
@@ -64,20 +60,22 @@ public:
SourceLocationContainer toSourceLocationContainer() const;
- CXTranslationUnit tu() const { return cxTranslationUnit; }
- CXSourceLocation cx() const { return cxSourceLocation; }
+ CXTranslationUnit tu() const { return m_cxTranslationUnit; }
+ CXSourceLocation cx() const { return m_cxSourceLocation; }
private:
operator CXSourceLocation() const;
+ void evaluate() const;
private:
- CXSourceLocation cxSourceLocation;
- CXTranslationUnit cxTranslationUnit;
- mutable Utf8String filePath_;
- uint line_ = 0;
- uint column_ = 0;
- uint offset_ = 0;
- mutable bool isFilePathNormalized_ = true;
+ CXSourceLocation m_cxSourceLocation;
+ CXTranslationUnit m_cxTranslationUnit;
+ mutable Utf8String m_filePath;
+ mutable uint m_line = 0;
+ mutable uint m_column = 0;
+ mutable uint m_offset = 0;
+ mutable bool m_isFilePathNormalized = true;
+ mutable bool m_isEvaluated = false;
};
std::ostream &operator<<(std::ostream &os, const SourceLocation &sourceLocation);
diff --git a/src/tools/clangbackend/source/sourcerange.cpp b/src/tools/clangbackend/source/sourcerange.cpp
index e3a7da6445..413ddd77fa 100644
--- a/src/tools/clangbackend/source/sourcerange.cpp
+++ b/src/tools/clangbackend/source/sourcerange.cpp
@@ -40,7 +40,7 @@ SourceRange::SourceRange()
SourceRange::SourceRange(const SourceLocation &start, const SourceLocation &end)
: cxSourceRange(clang_getRange(start, end)),
- cxTranslationUnit(start.cxTranslationUnit)
+ cxTranslationUnit(start.m_cxTranslationUnit)
{
}
diff --git a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri
index 6e965792bc..1e1dde72ec 100644
--- a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri
+++ b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri
@@ -26,7 +26,9 @@ HEADERS += \
$$PWD/collectusedmacroactionfactory.h \
$$PWD/collectusedmacrosaction.h \
$$PWD/collectusedmacrosandsourcespreprocessorcallbacks.h \
- $$PWD/usedmacrosandsourcescollector.h
+ $$PWD/usedmacrosandsourcescollector.h \
+ $$PWD/usedmacroandsourcestorageinterface.h \
+ $$PWD/usedmacroandsourcestorage.h
!isEmpty(LIBTOOLING_LIBS) {
SOURCES += \
diff --git a/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h b/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h
index 2a6d0a54d8..2754847711 100644
--- a/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h
+++ b/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h
@@ -70,7 +70,11 @@ public:
const clang::FileEntry *file,
llvm::StringRef /*searchPath*/,
llvm::StringRef /*relativePath*/,
- const clang::Module * /*imported*/) override
+ const clang::Module * /*imported*/
+#if LLVM_VERSION_MAJOR >= 7
+ , clang::SrcMgr::CharacteristicKind /*fileType*/
+#endif
+ ) override
{
if (!m_skipInclude && file) {
auto fileUID = file->getUID();
diff --git a/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h b/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h
index 1e3c7b7b64..48bd0ddec9 100644
--- a/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h
+++ b/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h
@@ -196,7 +196,11 @@ public:
const clang::FileEntry *file,
llvm::StringRef /*searchPath*/,
llvm::StringRef /*relativePath*/,
- const clang::Module * /*imported*/) override
+ const clang::Module * /*imported*/
+#if LLVM_VERSION_MAJOR >= 7
+ , clang::SrcMgr::CharacteristicKind /*fileType*/
+#endif
+ ) override
{
if (!m_skipInclude && file)
addSourceDependency(file, hashLocation);
diff --git a/src/tools/clangpchmanagerbackend/source/usedmacroandsourcestorage.h b/src/tools/clangpchmanagerbackend/source/usedmacroandsourcestorage.h
new file mode 100644
index 0000000000..ed45465c68
--- /dev/null
+++ b/src/tools/clangpchmanagerbackend/source/usedmacroandsourcestorage.h
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 "usedmacroandsourcestorageinterface.h"
+
+#include <compilermacro.h>
+#include <sqliteexception.h>
+#include <sqlitetable.h>
+#include <sqlitetransaction.h>
+
+#include <utils/smallstringview.h>
+
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+
+namespace ClangBackEnd {
+
+template<typename Database=Sqlite::Database>
+class UsedMacroAndSourceStorage final : public UsedMacroAndSourceStorageInterface
+{
+ using ReadStatement = typename Database::ReadStatement;
+ using WriteStatement = typename Database::WriteStatement;
+public:
+ UsedMacroAndSourceStorage(Database &database)
+ : m_transaction(database),
+ m_database(database)
+ {
+ m_transaction.commit();
+ }
+
+ void insertFileStatuses(const FileStatuses &fileStatuses) override
+ {
+ WriteStatement &statement = m_insertFileStatuses;
+
+ for (const FileStatus &fileStatus : fileStatuses)
+ statement.write(fileStatus.filePathId.filePathId,
+ fileStatus.size,
+ fileStatus.lastModified,
+ fileStatus.isInPrecompiledHeader);
+ }
+
+ long long fetchLowestLastModifiedTime(FilePathId sourceId) const override
+ {
+ ReadStatement &statement = m_getLowestLastModifiedTimeOfDependencies;
+
+ return statement.template value<long long>(sourceId.filePathId).value_or(0);
+ }
+
+ void insertOrUpdateUsedMacros(const UsedMacros &usedMacros) override
+ {
+ WriteStatement &insertStatement = m_insertIntoNewUsedMacrosStatement;
+ for (const UsedMacro &usedMacro : usedMacros)
+ insertStatement.write(usedMacro.filePathId.filePathId, usedMacro.macroName);
+
+ m_syncNewUsedMacrosStatement.execute();
+ m_deleteOutdatedUsedMacrosStatement.execute();
+ m_deleteNewUsedMacrosTableStatement.execute();
+ }
+
+ void insertOrUpdateSourceDependencies(const SourceDependencies &sourceDependencies) override
+ {
+ WriteStatement &insertStatement = m_insertIntoNewSourceDependenciesStatement;
+ for (SourceDependency sourceDependency : sourceDependencies)
+ insertStatement.write(sourceDependency.filePathId.filePathId,
+ sourceDependency.dependencyFilePathId.filePathId);
+
+ m_syncNewSourceDependenciesStatement.execute();
+ m_deleteOutdatedSourceDependenciesStatement.execute();
+ m_deleteNewSourceDependenciesStatement.execute();
+ }
+
+ static Utils::SmallString toJson(const Utils::SmallStringVector &strings)
+ {
+ QJsonDocument document;
+ QJsonArray array;
+
+ std::transform(strings.begin(), strings.end(), std::back_inserter(array), [] (const auto &string) {
+ return QJsonValue(string.data());
+ });
+
+ document.setArray(array);
+
+ return document.toJson(QJsonDocument::Compact);
+ }
+
+ static Utils::SmallString toJson(const CompilerMacros &compilerMacros)
+ {
+ QJsonDocument document;
+ QJsonObject object;
+
+ for (const CompilerMacro &macro : compilerMacros)
+ object.insert(QString(macro.key), QString(macro.value));
+
+ document.setObject(object);
+
+ return document.toJson(QJsonDocument::Compact);
+ }
+
+ Sqlite::Table createNewUsedMacrosTable() const
+ {
+ Sqlite::Table table;
+ table.setName("newUsedMacros");
+ table.setUseTemporaryTable(true);
+ const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer);
+ const Sqlite::Column &macroNameColumn = table.addColumn("macroName", Sqlite::ColumnType::Text);
+ table.addIndex({sourceIdColumn, macroNameColumn});
+
+ table.initialize(m_database);
+
+ return table;
+ }
+
+ Sqlite::Table createNewSourceDependenciesTable() const
+ {
+ Sqlite::Table table;
+ table.setName("newSourceDependencies");
+ table.setUseTemporaryTable(true);
+ const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer);
+ const Sqlite::Column &dependencySourceIdColumn = table.addColumn("dependencySourceId", Sqlite::ColumnType::Text);
+ table.addIndex({sourceIdColumn, dependencySourceIdColumn});
+
+ table.initialize(m_database);
+
+ return table;
+ }
+
+public:
+ Sqlite::ImmediateNonThrowingDestructorTransaction m_transaction;
+ Database &m_database;
+ Sqlite::Table newUsedMacroTable{createNewUsedMacrosTable()};
+ Sqlite::Table newNewSourceDependenciesTable{createNewSourceDependenciesTable()};
+ WriteStatement m_insertIntoNewUsedMacrosStatement{
+ "INSERT INTO newUsedMacros(sourceId, macroName) VALUES (?,?)",
+ m_database
+ };
+ WriteStatement m_syncNewUsedMacrosStatement{
+ "INSERT INTO usedMacros(sourceId, macroName) SELECT sourceId, macroName FROM newUsedMacros WHERE NOT EXISTS (SELECT sourceId FROM usedMacros WHERE usedMacros.sourceId == newUsedMacros.sourceId AND usedMacros.macroName == newUsedMacros.macroName)",
+ m_database
+ };
+ WriteStatement m_deleteOutdatedUsedMacrosStatement{
+ "DELETE FROM usedMacros WHERE sourceId IN (SELECT sourceId FROM newUsedMacros) AND NOT EXISTS (SELECT sourceId FROM newUsedMacros WHERE newUsedMacros.sourceId == usedMacros.sourceId AND newUsedMacros.macroName == usedMacros.macroName)",
+ m_database
+ };
+ WriteStatement m_deleteNewUsedMacrosTableStatement{
+ "DELETE FROM newUsedMacros",
+ m_database
+ };
+ mutable ReadStatement m_getLowestLastModifiedTimeOfDependencies{
+ "WITH RECURSIVE sourceIds(sourceId) AS (VALUES(?) UNION SELECT dependencySourceId FROM sourceDependencies, sourceIds WHERE sourceDependencies.sourceId = sourceIds.sourceId) SELECT min(lastModified) FROM fileStatuses, sourceIds WHERE fileStatuses.sourceId = sourceIds.sourceId",
+ m_database
+ };
+ WriteStatement m_insertIntoNewSourceDependenciesStatement{
+ "INSERT INTO newSourceDependencies(sourceId, dependencySourceId) VALUES (?,?)",
+ m_database
+ };
+ WriteStatement m_insertFileStatuses{
+ "INSERT OR REPLACE INTO fileStatuses(sourceId, size, lastModified, isInPrecompiledHeader) VALUES (?,?,?,?)",
+ m_database
+ };
+ WriteStatement m_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)",
+ m_database
+ };
+ WriteStatement m_deleteOutdatedSourceDependenciesStatement{
+ "DELETE FROM sourceDependencies WHERE sourceId IN (SELECT sourceId FROM newSourceDependencies) AND NOT EXISTS (SELECT sourceId FROM newSourceDependencies WHERE newSourceDependencies.sourceId == sourceDependencies.sourceId AND newSourceDependencies.dependencySourceId == sourceDependencies.dependencySourceId)",
+ m_database
+ };
+ WriteStatement m_deleteNewSourceDependenciesStatement{
+ "DELETE FROM newSourceDependencies",
+ m_database
+ };
+};
+}
diff --git a/src/tools/clangpchmanagerbackend/source/usedmacroandsourcestorageinterface.h b/src/tools/clangpchmanagerbackend/source/usedmacroandsourcestorageinterface.h
new file mode 100644
index 0000000000..2cbb9f84b5
--- /dev/null
+++ b/src/tools/clangpchmanagerbackend/source/usedmacroandsourcestorageinterface.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "filestatus.h"
+#include "sourcedependency.h"
+#include "usedmacro.h"
+
+namespace ClangBackEnd {
+
+class UsedMacroAndSourceStorageInterface
+{
+public:
+ UsedMacroAndSourceStorageInterface() = default;
+ UsedMacroAndSourceStorageInterface(const UsedMacroAndSourceStorageInterface &) = delete;
+ UsedMacroAndSourceStorageInterface &operator=(const UsedMacroAndSourceStorageInterface &) = delete;
+
+ virtual void insertOrUpdateUsedMacros(const UsedMacros &usedMacros) = 0;
+ virtual void insertFileStatuses(const FileStatuses &fileStatuses) = 0;
+ virtual void insertOrUpdateSourceDependencies(const SourceDependencies &sourceDependencies) = 0;
+ virtual long long fetchLowestLastModifiedTime(FilePathId sourceId) const = 0;
+
+
+protected:
+ ~UsedMacroAndSourceStorageInterface() = default;
+};
+
+} // namespace ClangBackEnd
+
diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri
index 26fa44aa68..fb1671aaf7 100644
--- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri
+++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri
@@ -9,7 +9,6 @@ HEADERS += \
$$PWD/symbolscollectorinterface.h \
$$PWD/symbolstorageinterface.h \
$$PWD/symbolstorage.h \
- $$PWD/storagesqlitestatementfactory.h \
$$PWD/symbolindexing.h \
$$PWD/symbolindexinginterface.h \
$$PWD/collectmacrospreprocessorcallbacks.h \
diff --git a/src/tools/clangrefactoringbackend/source/collectmacrospreprocessorcallbacks.h b/src/tools/clangrefactoringbackend/source/collectmacrospreprocessorcallbacks.h
index 9581e9790a..689e291098 100644
--- a/src/tools/clangrefactoringbackend/source/collectmacrospreprocessorcallbacks.h
+++ b/src/tools/clangrefactoringbackend/source/collectmacrospreprocessorcallbacks.h
@@ -95,7 +95,11 @@ public:
const clang::FileEntry *file,
llvm::StringRef /*searchPath*/,
llvm::StringRef /*relativePath*/,
- const clang::Module * /*imported*/) override
+ const clang::Module * /*imported*/
+#if LLVM_VERSION_MAJOR >= 7
+ , clang::SrcMgr::CharacteristicKind /*fileType*/
+#endif
+ ) override
{
if (!m_skipInclude && file)
addSourceDependency(file, hashLocation);
diff --git a/src/tools/clangrefactoringbackend/source/indexdataconsumer.cpp b/src/tools/clangrefactoringbackend/source/indexdataconsumer.cpp
index 01f5190c08..2c190c6a10 100644
--- a/src/tools/clangrefactoringbackend/source/indexdataconsumer.cpp
+++ b/src/tools/clangrefactoringbackend/source/indexdataconsumer.cpp
@@ -127,8 +127,12 @@ bool IndexDataConsumer::skipSymbol(clang::FileID fileId, clang::index::SymbolRol
bool IndexDataConsumer::handleDeclOccurence(const clang::Decl *declaration,
clang::index::SymbolRoleSet symbolRoles,
llvm::ArrayRef<clang::index::SymbolRelation> symbolRelations,
+#if LLVM_VERSION_MAJOR >= 7
+ clang::SourceLocation sourceLocation,
+#else
clang::FileID fileId,
unsigned offset,
+#endif
IndexDataConsumer::ASTNodeInfo astNodeInfo)
{
const auto *namedDeclaration = clang::dyn_cast<clang::NamedDecl>(declaration);
@@ -136,11 +140,17 @@ bool IndexDataConsumer::handleDeclOccurence(const clang::Decl *declaration,
if (!namedDeclaration->getIdentifier())
return true;
+#if LLVM_VERSION_MAJOR >= 7
+ if (skipSymbol(m_sourceManager->getFileID(sourceLocation), symbolRoles))
+#else
if (skipSymbol(fileId, symbolRoles))
+#endif
return true;
SymbolIndex globalId = toSymbolIndex(declaration->getCanonicalDecl());
+#if LLVM_VERSION_MAJOR < 7
clang::SourceLocation sourceLocation = m_sourceManager->getLocForStartOfFile(fileId).getLocWithOffset(offset);
+#endif
auto found = m_symbolEntries.find(globalId);
if (found == m_symbolEntries.end()) {
diff --git a/src/tools/clangrefactoringbackend/source/indexdataconsumer.h b/src/tools/clangrefactoringbackend/source/indexdataconsumer.h
index 1024d0f500..8524455574 100644
--- a/src/tools/clangrefactoringbackend/source/indexdataconsumer.h
+++ b/src/tools/clangrefactoringbackend/source/indexdataconsumer.h
@@ -55,8 +55,12 @@ public:
bool handleDeclOccurence(const clang::Decl *declaration,
clang::index::SymbolRoleSet symbolRoles,
llvm::ArrayRef<clang::index::SymbolRelation> symbolRelations,
+#if LLVM_VERSION_MAJOR >= 7
+ clang::SourceLocation sourceLocation,
+#else
clang::FileID fileId,
unsigned offset,
+#endif
ASTNodeInfo astNodeInfo) override;
private:
diff --git a/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h b/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h
deleted file mode 100644
index 7652795acb..0000000000
--- a/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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 <sqlitetransaction.h>
-#include <sqlitetable.h>
-
-namespace ClangBackEnd {
-
-template<typename DatabaseType>
-class StorageSqliteStatementFactory
-{
-public:
- using Database = DatabaseType;
- using ReadStatement = typename Database::ReadStatement;
- using WriteStatement = typename Database::WriteStatement;
-
- StorageSqliteStatementFactory(Database &database)
- : transaction(database),
- database(database)
- {
- transaction.commit();
- }
-
- Sqlite::Table createNewSymbolsTable() const
- {
- Sqlite::Table table;
- table.setName("newSymbols");
- table.setUseTemporaryTable(true);
- table.addColumn("temporarySymbolId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
- const Sqlite::Column &symbolIdColumn = table.addColumn("symbolId", Sqlite::ColumnType::Integer);
- const Sqlite::Column &usrColumn = table.addColumn("usr", Sqlite::ColumnType::Text);
- const Sqlite::Column &symbolNameColumn = table.addColumn("symbolName", Sqlite::ColumnType::Text);
- table.addColumn("symbolKind", Sqlite::ColumnType::Integer);
- table.addIndex({usrColumn, symbolNameColumn});
- table.addIndex({symbolIdColumn});
-
- table.initialize(database);
-
- return table;
- }
-
- Sqlite::Table createNewLocationsTable() const
- {
- Sqlite::Table table;
- table.setName("newLocations");
- table.setUseTemporaryTable(true);
- table.addColumn("temporarySymbolId", Sqlite::ColumnType::Integer);
- table.addColumn("symbolId", Sqlite::ColumnType::Integer);
- const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer);
- const Sqlite::Column &lineColumn = table.addColumn("line", Sqlite::ColumnType::Integer);
- const Sqlite::Column &columnColumn = table.addColumn("column", Sqlite::ColumnType::Integer);
- table.addColumn("locationKind", Sqlite::ColumnType::Integer);
- table.addUniqueIndex({sourceIdColumn, lineColumn, columnColumn});
-
- table.initialize(database);
-
- return table;
- }
-
- Sqlite::Table createNewUsedMacrosTable() const
- {
- Sqlite::Table table;
- table.setName("newUsedMacros");
- table.setUseTemporaryTable(true);
- const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer);
- const Sqlite::Column &macroNameColumn = table.addColumn("macroName", Sqlite::ColumnType::Text);
- table.addIndex({sourceIdColumn, macroNameColumn});
-
- table.initialize(database);
-
- return table;
- }
-
- Sqlite::Table createNewSourceDependenciesTable() const
- {
- Sqlite::Table table;
- table.setName("newSourceDependencies");
- table.setUseTemporaryTable(true);
- const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer);
- const Sqlite::Column &dependencySourceIdColumn = table.addColumn("dependencySourceId", Sqlite::ColumnType::Text);
- table.addIndex({sourceIdColumn, dependencySourceIdColumn});
-
- table.initialize(database);
-
- return table;
- }
-
-public:
- Sqlite::ImmediateNonThrowingDestructorTransaction transaction;
- Database &database;
- Sqlite::Table newSymbolsTablet{createNewSymbolsTable()};
- Sqlite::Table newLocationsTable{createNewLocationsTable()};
- Sqlite::Table newUsedMacroTable{createNewUsedMacrosTable()};
- Sqlite::Table newNewSourceDependenciesTable{createNewSourceDependenciesTable()};
- WriteStatement insertSymbolsToNewSymbolsStatement{
- "INSERT INTO newSymbols(temporarySymbolId, usr, symbolName, symbolKind) VALUES(?,?,?,?)",
- database};
- WriteStatement insertLocationsToNewLocationsStatement{
- "INSERT OR IGNORE INTO newLocations(temporarySymbolId, line, column, sourceId, locationKind) VALUES(?,?,?,?,?)",
- database
- };
- ReadStatement selectNewSourceIdsStatement{
- "SELECT DISTINCT sourceId FROM newLocations WHERE NOT EXISTS (SELECT sourceId FROM sources WHERE newLocations.sourceId == sources.sourceId)",
- database
- };
- WriteStatement addNewSymbolsToSymbolsStatement{
- "INSERT INTO symbols(usr, symbolName, symbolKind) "
- "SELECT usr, symbolName, symbolKind FROM newSymbols WHERE NOT EXISTS "
- "(SELECT usr FROM symbols WHERE symbols.usr == newSymbols.usr)",
- database
- };
- WriteStatement syncNewSymbolsFromSymbolsStatement{
- "UPDATE newSymbols SET symbolId = (SELECT symbolId FROM symbols WHERE newSymbols.usr = symbols.usr)",
- database
- };
- WriteStatement syncSymbolsIntoNewLocationsStatement{
- "UPDATE newLocations SET symbolId = (SELECT symbolId FROM newSymbols WHERE newSymbols.temporarySymbolId = newLocations.temporarySymbolId)",
- database
- };
- WriteStatement deleteAllLocationsFromUpdatedFilesStatement{
- "DELETE FROM locations WHERE sourceId IN (SELECT DISTINCT sourceId FROM newLocations)",
- database
- };
- WriteStatement insertNewLocationsInLocationsStatement{
- "INSERT INTO locations(symbolId, line, column, sourceId, locationKind) SELECT symbolId, line, column, sourceId, locationKind FROM newLocations",
- database
- };
- WriteStatement deleteNewSymbolsTableStatement{
- "DELETE FROM newSymbols",
- database
- };
- WriteStatement deleteNewLocationsTableStatement{
- "DELETE FROM newLocations",
- database
- };
- WriteStatement insertProjectPartStatement{
- "INSERT OR IGNORE INTO projectParts(projectPartName, compilerArguments, compilerMacros, includeSearchPaths) VALUES (?,?,?,?)",
- database
- };
- WriteStatement updateProjectPartStatement{
- "UPDATE projectParts SET compilerArguments = ?, compilerMacros = ?, includeSearchPaths = ? WHERE projectPartName = ?",
- database
- };
- ReadStatement getProjectPartIdStatement{
- "SELECT projectPartId FROM projectParts WHERE projectPartName = ?",
- database
- };
- WriteStatement deleteAllProjectPartsSourcesWithProjectPartIdStatement{
- "DELETE FROM projectPartsSources WHERE projectPartId = ?",
- database
- };
- WriteStatement insertProjectPartSourcesStatement{
- "INSERT INTO projectPartsSources(projectPartId, sourceId) VALUES (?,?)",
- database
- };
- ReadStatement getCompileArgumentsForFileIdStatement{
- "SELECT compilerArguments FROM projectParts WHERE projectPartId = (SELECT projectPartId FROM projectPartsSources WHERE sourceId = ?)",
- database
- };
- WriteStatement insertIntoNewUsedMacrosStatement{
- "INSERT INTO newUsedMacros(sourceId, macroName) VALUES (?,?)",
- database
- };
- WriteStatement syncNewUsedMacrosStatement{
- "INSERT INTO usedMacros(sourceId, macroName) SELECT sourceId, macroName FROM newUsedMacros WHERE NOT EXISTS (SELECT sourceId FROM usedMacros WHERE usedMacros.sourceId == newUsedMacros.sourceId AND usedMacros.macroName == newUsedMacros.macroName)",
- database
- };
- WriteStatement deleteOutdatedUsedMacrosStatement{
- "DELETE FROM usedMacros WHERE sourceId IN (SELECT sourceId FROM newUsedMacros) AND NOT EXISTS (SELECT sourceId FROM newUsedMacros WHERE newUsedMacros.sourceId == usedMacros.sourceId AND newUsedMacros.macroName == usedMacros.macroName)",
- database
- };
- WriteStatement deleteNewUsedMacrosTableStatement{
- "DELETE FROM newUsedMacros",
- database
- };
- WriteStatement insertFileStatuses{
- "INSERT OR REPLACE INTO fileStatuses(sourceId, size, lastModified, isInPrecompiledHeader) VALUES (?,?,?,?)",
- database
- };
- WriteStatement insertIntoNewSourceDependenciesStatement{
- "INSERT INTO newSourceDependencies(sourceId, dependencySourceId) VALUES (?,?)",
- 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
- };
- WriteStatement deleteOutdatedSourceDependenciesStatement{
- "DELETE FROM sourceDependencies WHERE sourceId IN (SELECT sourceId FROM newSourceDependencies) AND NOT EXISTS (SELECT sourceId FROM newSourceDependencies WHERE newSourceDependencies.sourceId == sourceDependencies.sourceId AND newSourceDependencies.dependencySourceId == sourceDependencies.dependencySourceId)",
- database
- };
- WriteStatement deleteNewSourceDependenciesStatement{
- "DELETE FROM newSourceDependencies",
- database
- };
- ReadStatement getProjectPartArtefactsBySourceId{
- "SELECT compilerArguments, compilerMacros, includeSearchPaths, projectPartId FROM projectParts WHERE projectPartId = (SELECT projectPartId FROM projectPartsSources WHERE sourceId = ?)",
- database
- };
- ReadStatement getProjectPartArtefactsByProjectPartName{
- "SELECT compilerArguments, compilerMacros, includeSearchPaths, projectPartId FROM projectParts WHERE projectPartName = ?",
- database
- };
- ReadStatement getLowestLastModifiedTimeOfDependencies{
- "WITH RECURSIVE sourceIds(sourceId) AS (VALUES(?) UNION SELECT dependencySourceId FROM sourceDependencies, sourceIds WHERE sourceDependencies.sourceId = sourceIds.sourceId) SELECT min(lastModified) FROM fileStatuses, sourceIds WHERE fileStatuses.sourceId = sourceIds.sourceId",
- database
- };
- ReadStatement getPrecompiledHeader{
- "SELECT pchPath, pchBuildTime FROM precompiledHeaders WHERE projectPartId = ?",
- database
- };
-};
-} // namespace ClangBackEnd
diff --git a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp
index 272e89fa89..02a2fd14a0 100644
--- a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp
+++ b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp
@@ -58,12 +58,14 @@ private:
SymbolIndexer::SymbolIndexer(SymbolIndexerTaskQueueInterface &symbolIndexerTaskQueue,
SymbolStorageInterface &symbolStorage,
+ UsedMacroAndSourceStorageInterface &usedMacroAndSourceStorage,
ClangPathWatcherInterface &pathWatcher,
FilePathCachingInterface &filePathCache,
FileStatusCache &fileStatusCache,
Sqlite::TransactionInterface &transactionInterface)
: m_symbolIndexerTaskQueue(symbolIndexerTaskQueue),
m_symbolStorage(symbolStorage),
+ m_usedMacroAndSourceStorage(usedMacroAndSourceStorage),
m_pathWatcher(pathWatcher),
m_filePathCache(filePathCache),
m_fileStatusCache(fileStatusCache),
@@ -115,11 +117,11 @@ void SymbolIndexer::updateProjectPart(V2::ProjectPartContainer &&projectPart)
m_symbolStorage.updateProjectPartSources(projectPartId,
symbolsCollector.sourceFiles());
- m_symbolStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros());
+ m_usedMacroAndSourceStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros());
- m_symbolStorage.insertFileStatuses(symbolsCollector.fileStatuses());
+ m_usedMacroAndSourceStorage.insertFileStatuses(symbolsCollector.fileStatuses());
- m_symbolStorage.insertOrUpdateSourceDependencies(symbolsCollector.sourceDependencies());
+ m_usedMacroAndSourceStorage.insertOrUpdateSourceDependencies(symbolsCollector.sourceDependencies());
transaction.commit();
};
@@ -180,11 +182,11 @@ void SymbolIndexer::updateChangedPath(FilePathId filePathId,
m_symbolStorage.updateProjectPartSources(projectPartId, symbolsCollector.sourceFiles());
- m_symbolStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros());
+ m_usedMacroAndSourceStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros());
- m_symbolStorage.insertFileStatuses(symbolsCollector.fileStatuses());
+ m_usedMacroAndSourceStorage.insertFileStatuses(symbolsCollector.fileStatuses());
- m_symbolStorage.insertOrUpdateSourceDependencies(symbolsCollector.sourceDependencies());
+ m_usedMacroAndSourceStorage.insertOrUpdateSourceDependencies(symbolsCollector.sourceDependencies());
transaction.commit();
};
@@ -212,7 +214,7 @@ FilePathIds SymbolIndexer::filterChangedFiles(const V2::ProjectPartContainer &pr
ids.reserve(projectPart.sourcePathIds.size());
for (const FilePathId &sourceId : projectPart.sourcePathIds) {
- long long oldLastModified = m_symbolStorage.fetchLowestLastModifiedTime(sourceId);
+ long long oldLastModified = m_usedMacroAndSourceStorage.fetchLowestLastModifiedTime(sourceId);
long long currentLastModified = m_fileStatusCache.lastModifiedTime(sourceId);
if (oldLastModified < currentLastModified)
ids.push_back(sourceId);
diff --git a/src/tools/clangrefactoringbackend/source/symbolindexer.h b/src/tools/clangrefactoringbackend/source/symbolindexer.h
index 6d1a1de50b..6e96e2fee5 100644
--- a/src/tools/clangrefactoringbackend/source/symbolindexer.h
+++ b/src/tools/clangrefactoringbackend/source/symbolindexer.h
@@ -28,6 +28,7 @@
#include "filestatuscache.h"
#include "symbolindexertaskqueueinterface.h"
#include "symbolstorageinterface.h"
+#include "usedmacroandsourcestorageinterface.h"
#include "clangpathwatcher.h"
#include <projectpartcontainerv2.h>
@@ -42,6 +43,7 @@ class SymbolIndexer final : public ClangPathWatcherNotifier
public:
SymbolIndexer(SymbolIndexerTaskQueueInterface &symbolIndexerTaskQueue,
SymbolStorageInterface &symbolStorage,
+ UsedMacroAndSourceStorageInterface &usedMacroAndSourceStorage,
ClangPathWatcherInterface &pathWatcher,
FilePathCachingInterface &filePathCache,
FileStatusCache &fileStatusCache,
@@ -71,6 +73,7 @@ public:
private:
SymbolIndexerTaskQueueInterface &m_symbolIndexerTaskQueue;
SymbolStorageInterface &m_symbolStorage;
+ UsedMacroAndSourceStorageInterface &m_usedMacroAndSourceStorage;
ClangPathWatcherInterface &m_pathWatcher;
FilePathCachingInterface &m_filePathCache;
FileStatusCache &m_fileStatusCache;
diff --git a/src/tools/clangrefactoringbackend/source/symbolindexing.h b/src/tools/clangrefactoringbackend/source/symbolindexing.h
index 6189fe23ae..488e73be9e 100644
--- a/src/tools/clangrefactoringbackend/source/symbolindexing.h
+++ b/src/tools/clangrefactoringbackend/source/symbolindexing.h
@@ -27,7 +27,6 @@
#include "symbolindexinginterface.h"
-#include "storagesqlitestatementfactory.h"
#include "symbolindexer.h"
#include "symbolscollector.h"
#include "processormanager.h"
@@ -35,6 +34,8 @@
#include "taskscheduler.h"
#include "symbolstorage.h"
+#include <usedmacroandsourcestorage.h>
+
#include <refactoringdatabaseinitializer.h>
#include <filepathcachingfwd.h>
@@ -74,14 +75,15 @@ private:
class SymbolIndexing final : public SymbolIndexingInterface
{
public:
- using StatementFactory = ClangBackEnd::StorageSqliteStatementFactory<Sqlite::Database>;
- using Storage = ClangBackEnd::SymbolStorage<StatementFactory>;
+ using UsedMacroAndSourceStorage = ClangBackEnd::UsedMacroAndSourceStorage<Sqlite::Database>;
+ using SymbolStorage = ClangBackEnd::SymbolStorage<Sqlite::Database>;
SymbolIndexing(Sqlite::Database &database,
FilePathCachingInterface &filePathCache,
const GeneratedFiles &generatedFiles,
ProgressCounter::SetProgressCallback &&setProgressCallback)
: m_filePathCache(filePathCache),
- m_statementFactory(database),
+ m_usedMacroAndSourceStorage(database),
+ m_symbolStorage(database),
m_collectorManger(generatedFiles, database),
m_progressCounter(std::move(setProgressCallback)),
m_indexerScheduler(m_collectorManger, m_indexerQueue, m_progressCounter, std::thread::hardware_concurrency())
@@ -112,8 +114,8 @@ public:
private:
using SymbolIndexerTaskScheduler = TaskScheduler<SymbolsCollectorManager, SymbolIndexerTask::Callable>;
FilePathCachingInterface &m_filePathCache;
- StatementFactory m_statementFactory;
- Storage m_symbolStorage{m_statementFactory};
+ UsedMacroAndSourceStorage m_usedMacroAndSourceStorage;
+ SymbolStorage m_symbolStorage;
ClangPathWatcher<QFileSystemWatcher, QTimer> m_sourceWatcher{m_filePathCache};
FileStatusCache m_fileStatusCache{m_filePathCache};
SymbolsCollectorManager m_collectorManger;
@@ -122,10 +124,11 @@ private:
SymbolIndexerTaskQueue m_indexerQueue{m_indexerScheduler, m_progressCounter};
SymbolIndexer m_indexer{m_indexerQueue,
m_symbolStorage,
+ m_usedMacroAndSourceStorage,
m_sourceWatcher,
m_filePathCache,
m_fileStatusCache,
- m_statementFactory.database};
+ m_symbolStorage.m_database};
};
} // namespace ClangBackEnd
diff --git a/src/tools/clangrefactoringbackend/source/symbolstorage.h b/src/tools/clangrefactoringbackend/source/symbolstorage.h
index 4de47dab1d..4aae17c599 100644
--- a/src/tools/clangrefactoringbackend/source/symbolstorage.h
+++ b/src/tools/clangrefactoringbackend/source/symbolstorage.h
@@ -27,9 +27,10 @@
#include "symbolstorageinterface.h"
+#include <filepathcachingfwd.h>
#include <sqliteexception.h>
#include <sqlitetransaction.h>
-#include <filepathcachingfwd.h>
+#include <sqlitetable.h>
#include <QJsonArray>
#include <QJsonDocument>
@@ -37,17 +38,19 @@
namespace ClangBackEnd {
-template <typename StatementFactory>
+template <typename DatabaseType>
class SymbolStorage final : public SymbolStorageInterface
{
- using ReadStatement = typename StatementFactory::ReadStatement;
- using WriteStatement = typename StatementFactory::WriteStatement;
- using Database = typename StatementFactory::Database;
+ using Database = DatabaseType;
+ using ReadStatement = typename Database::ReadStatement;
+ using WriteStatement = typename Database::WriteStatement;
public:
- SymbolStorage(StatementFactory &statementFactory)
- : m_statementFactory(statementFactory)
+ SymbolStorage(Database &database)
+ : m_transaction(database),
+ m_database(database)
{
+ m_transaction.commit();
}
void addSymbolsAndSourceLocations(const SymbolEntries &symbolEntries,
@@ -69,95 +72,54 @@ public:
const CompilerMacros &compilerMacros,
const Utils::SmallStringVector &includeSearchPaths) override
{
- m_statementFactory.database.setLastInsertedRowId(-1);
+ m_database.setLastInsertedRowId(-1);
Utils::SmallString compilerArguementsAsJson = toJson(commandLineArguments);
Utils::SmallString compilerMacrosAsJson = toJson(compilerMacros);
Utils::SmallString includeSearchPathsAsJason = toJson(includeSearchPaths);
- WriteStatement &insertStatement = m_statementFactory.insertProjectPartStatement;
+ WriteStatement &insertStatement = m_insertProjectPartStatement;
insertStatement.write(projectPartName,
compilerArguementsAsJson,
compilerMacrosAsJson,
includeSearchPathsAsJason);
- if (m_statementFactory.database.lastInsertedRowId() == -1) {
- WriteStatement &updateStatement = m_statementFactory.updateProjectPartStatement;
+ if (m_database.lastInsertedRowId() == -1) {
+ WriteStatement &updateStatement = m_updateProjectPartStatement;
updateStatement.write(compilerArguementsAsJson,
compilerMacrosAsJson,
includeSearchPathsAsJason,
projectPartName);
}
- return int(m_statementFactory.database.lastInsertedRowId());
+ return int(m_database.lastInsertedRowId());
}
Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact(FilePathId sourceId) const override
{
- ReadStatement &statement = m_statementFactory.getProjectPartArtefactsBySourceId;
+ ReadStatement &statement = m_getProjectPartArtefactsBySourceId;
return statement.template value<ProjectPartArtefact, 4>(sourceId.filePathId);
}
Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact(Utils::SmallStringView projectPartName) const override
{
- ReadStatement &statement = m_statementFactory.getProjectPartArtefactsByProjectPartName;
+ ReadStatement &statement = m_getProjectPartArtefactsByProjectPartName;
return statement.template value<ProjectPartArtefact, 4>(projectPartName);
}
- long long fetchLowestLastModifiedTime(FilePathId sourceId) const override
- {
- ReadStatement &statement = m_statementFactory.getLowestLastModifiedTimeOfDependencies;
-
- return statement.template value<long long>(sourceId.filePathId).value_or(0);
- }
-
- void insertOrUpdateUsedMacros(const UsedMacros &usedMacros) override
- {
- WriteStatement &insertStatement = m_statementFactory.insertIntoNewUsedMacrosStatement;
- for (const UsedMacro &usedMacro : usedMacros)
- insertStatement.write(usedMacro.filePathId.filePathId, usedMacro.macroName);
-
- m_statementFactory.syncNewUsedMacrosStatement.execute();
- m_statementFactory.deleteOutdatedUsedMacrosStatement.execute();
- m_statementFactory.deleteNewUsedMacrosTableStatement.execute();
- }
-
- void insertOrUpdateSourceDependencies(const SourceDependencies &sourceDependencies) override
- {
- WriteStatement &insertStatement = m_statementFactory.insertIntoNewSourceDependenciesStatement;
- for (SourceDependency sourceDependency : sourceDependencies)
- insertStatement.write(sourceDependency.filePathId.filePathId,
- sourceDependency.dependencyFilePathId.filePathId);
-
- m_statementFactory.syncNewSourceDependenciesStatement.execute();
- m_statementFactory.deleteOutdatedSourceDependenciesStatement.execute();
- m_statementFactory.deleteNewSourceDependenciesStatement.execute();
- }
-
void updateProjectPartSources(int projectPartId,
const FilePathIds &sourceFilePathIds) override
{
- WriteStatement &deleteStatement = m_statementFactory.deleteAllProjectPartsSourcesWithProjectPartIdStatement;
+ WriteStatement &deleteStatement = m_deleteAllProjectPartsSourcesWithProjectPartIdStatement;
deleteStatement.write(projectPartId);
- WriteStatement &insertStatement = m_statementFactory.insertProjectPartSourcesStatement;
+ WriteStatement &insertStatement = m_insertProjectPartSourcesStatement;
for (const FilePathId &sourceFilePathId : sourceFilePathIds)
insertStatement.write(projectPartId, sourceFilePathId.filePathId);
}
- void insertFileStatuses(const FileStatuses &fileStatuses)
- {
- WriteStatement &statement = m_statementFactory.insertFileStatuses;
-
- for (const FileStatus &fileStatus : fileStatuses)
- statement.write(fileStatus.filePathId.filePathId,
- fileStatus.size,
- fileStatus.lastModified,
- fileStatus.isInPrecompiledHeader);
- }
-
static Utils::SmallString toJson(const Utils::SmallStringVector &strings)
{
QJsonDocument document;
@@ -187,7 +149,7 @@ public:
void fillTemporarySymbolsTable(const SymbolEntries &symbolEntries)
{
- WriteStatement &statement = m_statementFactory.insertSymbolsToNewSymbolsStatement;
+ WriteStatement &statement = m_insertSymbolsToNewSymbolsStatement;
for (const auto &symbolEntry : symbolEntries) {
statement.write(symbolEntry.first,
@@ -199,7 +161,7 @@ public:
void fillTemporaryLocationsTable(const SourceLocationEntries &sourceLocations)
{
- WriteStatement &statement = m_statementFactory.insertLocationsToNewLocationsStatement;
+ WriteStatement &statement = m_insertLocationsToNewLocationsStatement;
for (const auto &locationEntry : sourceLocations) {
statement.write(locationEntry.symbolId,
@@ -212,42 +174,42 @@ public:
void addNewSymbolsToSymbols()
{
- m_statementFactory.addNewSymbolsToSymbolsStatement.execute();
+ m_addNewSymbolsToSymbolsStatement.execute();
}
void syncNewSymbolsFromSymbols()
{
- m_statementFactory.syncNewSymbolsFromSymbolsStatement.execute();
+ m_syncNewSymbolsFromSymbolsStatement.execute();
}
void syncSymbolsIntoNewLocations()
{
- m_statementFactory.syncSymbolsIntoNewLocationsStatement.execute();
+ m_syncSymbolsIntoNewLocationsStatement.execute();
}
void deleteAllLocationsFromUpdatedFiles()
{
- m_statementFactory.deleteAllLocationsFromUpdatedFilesStatement.execute();
+ m_deleteAllLocationsFromUpdatedFilesStatement.execute();
}
void insertNewLocationsInLocations()
{
- m_statementFactory.insertNewLocationsInLocationsStatement.execute();
+ m_insertNewLocationsInLocationsStatement.execute();
}
void deleteNewSymbolsTable()
{
- m_statementFactory.deleteNewSymbolsTableStatement.execute();
+ m_deleteNewSymbolsTableStatement.execute();
}
void deleteNewLocationsTable()
{
- m_statementFactory.deleteNewLocationsTableStatement.execute();
+ m_deleteNewLocationsTableStatement.execute();
}
Utils::optional<ProjectPartPch> fetchPrecompiledHeader(int projectPartId) const
{
- return m_statementFactory.getPrecompiledHeader.template value<ProjectPartPch, 2>(projectPartId);
+ return m_getPrecompiledHeader.template value<ProjectPartPch, 2>(projectPartId);
}
SourceLocationEntries sourceLocations() const
@@ -255,8 +217,124 @@ public:
return SourceLocationEntries();
}
-private:
- StatementFactory &m_statementFactory;
+ Sqlite::Table createNewSymbolsTable() const
+ {
+ Sqlite::Table table;
+ table.setName("newSymbols");
+ table.setUseTemporaryTable(true);
+ table.addColumn("temporarySymbolId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
+ const Sqlite::Column &symbolIdColumn = table.addColumn("symbolId", Sqlite::ColumnType::Integer);
+ const Sqlite::Column &usrColumn = table.addColumn("usr", Sqlite::ColumnType::Text);
+ const Sqlite::Column &symbolNameColumn = table.addColumn("symbolName", Sqlite::ColumnType::Text);
+ table.addColumn("symbolKind", Sqlite::ColumnType::Integer);
+ table.addIndex({usrColumn, symbolNameColumn});
+ table.addIndex({symbolIdColumn});
+
+ table.initialize(m_database);
+
+ return table;
+ }
+
+ Sqlite::Table createNewLocationsTable() const
+ {
+ Sqlite::Table table;
+ table.setName("newLocations");
+ table.setUseTemporaryTable(true);
+ table.addColumn("temporarySymbolId", Sqlite::ColumnType::Integer);
+ table.addColumn("symbolId", Sqlite::ColumnType::Integer);
+ const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer);
+ const Sqlite::Column &lineColumn = table.addColumn("line", Sqlite::ColumnType::Integer);
+ const Sqlite::Column &columnColumn = table.addColumn("column", Sqlite::ColumnType::Integer);
+ table.addColumn("locationKind", Sqlite::ColumnType::Integer);
+ table.addUniqueIndex({sourceIdColumn, lineColumn, columnColumn});
+
+ table.initialize(m_database);
+
+ return table;
+ }
+
+public:
+ Sqlite::ImmediateNonThrowingDestructorTransaction m_transaction;
+ Database &m_database;
+ Sqlite::Table newSymbolsTablet{createNewSymbolsTable()};
+ Sqlite::Table newLocationsTable{createNewLocationsTable()};
+ WriteStatement m_insertSymbolsToNewSymbolsStatement{
+ "INSERT INTO newSymbols(temporarySymbolId, usr, symbolName, symbolKind) VALUES(?,?,?,?)",
+ m_database};
+ WriteStatement m_insertLocationsToNewLocationsStatement{
+ "INSERT OR IGNORE INTO newLocations(temporarySymbolId, line, column, sourceId, locationKind) VALUES(?,?,?,?,?)",
+ m_database
+ };
+ ReadStatement m_selectNewSourceIdsStatement{
+ "SELECT DISTINCT sourceId FROM newLocations WHERE NOT EXISTS (SELECT sourceId FROM sources WHERE newLocations.sourceId == sources.sourceId)",
+ m_database
+ };
+ WriteStatement m_addNewSymbolsToSymbolsStatement{
+ "INSERT INTO symbols(usr, symbolName, symbolKind) "
+ "SELECT usr, symbolName, symbolKind FROM newSymbols WHERE NOT EXISTS "
+ "(SELECT usr FROM symbols WHERE symbols.usr == newSymbols.usr)",
+ m_database
+ };
+ WriteStatement m_syncNewSymbolsFromSymbolsStatement{
+ "UPDATE newSymbols SET symbolId = (SELECT symbolId FROM symbols WHERE newSymbols.usr = symbols.usr)",
+ m_database
+ };
+ WriteStatement m_syncSymbolsIntoNewLocationsStatement{
+ "UPDATE newLocations SET symbolId = (SELECT symbolId FROM newSymbols WHERE newSymbols.temporarySymbolId = newLocations.temporarySymbolId)",
+ m_database
+ };
+ WriteStatement m_deleteAllLocationsFromUpdatedFilesStatement{
+ "DELETE FROM locations WHERE sourceId IN (SELECT DISTINCT sourceId FROM newLocations)",
+ m_database
+ };
+ WriteStatement m_insertNewLocationsInLocationsStatement{
+ "INSERT INTO locations(symbolId, line, column, sourceId, locationKind) SELECT symbolId, line, column, sourceId, locationKind FROM newLocations",
+ m_database
+ };
+ WriteStatement m_deleteNewSymbolsTableStatement{
+ "DELETE FROM newSymbols",
+ m_database
+ };
+ WriteStatement m_deleteNewLocationsTableStatement{
+ "DELETE FROM newLocations",
+ m_database
+ };
+ WriteStatement m_insertProjectPartStatement{
+ "INSERT OR IGNORE INTO projectParts(projectPartName, compilerArguments, compilerMacros, includeSearchPaths) VALUES (?,?,?,?)",
+ m_database
+ };
+ WriteStatement m_updateProjectPartStatement{
+ "UPDATE projectParts SET compilerArguments = ?, compilerMacros = ?, includeSearchPaths = ? WHERE projectPartName = ?",
+ m_database
+ };
+ mutable ReadStatement m_getProjectPartIdStatement{
+ "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 compilerArguments FROM projectParts WHERE projectPartId = (SELECT projectPartId FROM projectPartsSources WHERE sourceId = ?)",
+ m_database
+ };
+ mutable ReadStatement m_getProjectPartArtefactsBySourceId{
+ "SELECT compilerArguments, compilerMacros, includeSearchPaths, projectPartId FROM projectParts WHERE projectPartId = (SELECT projectPartId FROM projectPartsSources WHERE sourceId = ?)",
+ m_database
+ };
+ mutable ReadStatement m_getProjectPartArtefactsByProjectPartName{
+ "SELECT compilerArguments, compilerMacros, includeSearchPaths, projectPartId FROM projectParts WHERE projectPartName = ?",
+ m_database
+ };
+ mutable ReadStatement m_getPrecompiledHeader{
+ "SELECT pchPath, pchBuildTime FROM precompiledHeaders WHERE projectPartId = ?",
+ m_database
+ };
};
} // namespace ClangBackEnd
diff --git a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h
index 0ade62cc44..0cb1dafd4f 100644
--- a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h
+++ b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h
@@ -55,12 +55,8 @@ public:
const Utils::SmallStringVector &includeSearchPaths) = 0;
virtual void updateProjectPartSources(int projectPartId,
const FilePathIds &sourceFilePathIds) = 0;
- virtual void insertOrUpdateUsedMacros(const UsedMacros &usedMacros) = 0;
- virtual void insertFileStatuses(const FileStatuses &fileStatuses) = 0;
- virtual void insertOrUpdateSourceDependencies(const SourceDependencies &sourceDependencies) = 0;
virtual Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact(FilePathId sourceId) const = 0;
virtual Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact(Utils::SmallStringView projectPartName) const = 0;
- virtual long long fetchLowestLastModifiedTime(FilePathId sourceId) const = 0;
virtual Utils::optional<ProjectPartPch> fetchPrecompiledHeader(int projectPartId) const = 0;
protected: