Merge remote-tracking branch 'origin/master' into 4.9

Change-Id: I0768e59f13f2fae0bdf13047431de9fac870bf74
This commit is contained in:
Eike Ziller
2019-02-07 07:43:26 +01:00
57 changed files with 879 additions and 510 deletions

4
.gitignore vendored
View File

@@ -27,8 +27,8 @@
*~ *~
.#* .#*
.DS_Store .DS_Store
/.qmake.cache .qmake.cache
/.qmake.stash .qmake.stash
Makefile* Makefile*
Thumbs.db Thumbs.db
core core

View File

@@ -656,7 +656,9 @@ QObject *ObjectNodeInstance::createPrimitiveFromSource(const QString &typeName,
if (parts.isEmpty()) if (parts.isEmpty())
return 0; return 0;
const QString importString = parts.join(".") + " " + QString::number(majorNumber) + "." + QString::number(minorNumber); QString importString = parts.join(".") + " " + QString::number(majorNumber) + "." + QString::number(minorNumber);
if (importString == "QtQuick 1.0") /* Workaround for implicit QQml import */
importString = "QtQuick 2.0";
QString source = "import " + importString + "\n" + unqualifiedTypeName + " {\n" + "}\n"; QString source = "import " + importString + "\n" + unqualifiedTypeName + " {\n" + "}\n";
return createCustomParserObject(source, "", context); return createCustomParserObject(source, "", context);
} }

View File

@@ -188,9 +188,7 @@ void QtTestOutputReader::processXMLOutput(const QByteArray &outputLine)
if (m_className.isEmpty() && outputLine.trimmed().isEmpty()) if (m_className.isEmpty() && outputLine.trimmed().isEmpty())
return; return;
// avoid encoding problems for Quick tests m_xmlReader.addData(QString::fromUtf8(outputLine));
m_xmlReader.addData(m_testType == TestType::QuickTest ? QString::fromLatin1(outputLine)
: QString::fromLocal8Bit(outputLine));
while (!m_xmlReader.atEnd()) { while (!m_xmlReader.atEnd()) {
if (m_futureInterface.isCanceled()) if (m_futureInterface.isCanceled())
return; return;

View File

@@ -55,6 +55,8 @@ TestResult::TestResult(const QString &id, const QString &name)
const QString TestResult::outputString(bool selected) const const QString TestResult::outputString(bool selected) const
{ {
if (m_result == Result::Application)
return m_id;
return selected ? m_description : m_description.split('\n').first(); return selected ? m_description : m_description.split('\n').first();
} }
@@ -145,6 +147,7 @@ QString TestResult::resultToString(const Result::Type type)
case Result::BlacklistedXFail: case Result::BlacklistedXFail:
return QString("BXFAIL"); return QString("BXFAIL");
case Result::MessageLocation: case Result::MessageLocation:
case Result::Application:
return QString(); return QString();
default: default:
if (type >= Result::INTERNAL_MESSAGES_BEGIN && type <= Result::INTERNAL_MESSAGES_END) if (type >= Result::INTERNAL_MESSAGES_BEGIN && type <= Result::INTERNAL_MESSAGES_END)

View File

@@ -67,6 +67,8 @@ enum Type {
MessageIntermediate, MessageIntermediate,
MessageCurrentTest, INTERNAL_MESSAGES_END = MessageCurrentTest, MessageCurrentTest, INTERNAL_MESSAGES_END = MessageCurrentTest,
Application,
Invalid, Invalid,
LAST_TYPE = Invalid LAST_TYPE = Invalid
}; };

View File

@@ -24,9 +24,12 @@
****************************************************************************/ ****************************************************************************/
#include "autotesticons.h" #include "autotesticons.h"
#include "autotestplugin.h"
#include "testresultdelegate.h" #include "testresultdelegate.h"
#include "testresultmodel.h" #include "testresultmodel.h"
#include "testsettings.h"
#include <projectexplorer/projectexplorericons.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QFontMetrics> #include <QFontMetrics>
@@ -62,6 +65,7 @@ static QIcon testResultIcon(Result::Type result) {
QIcon(), QIcon(),
Icons::RESULT_MESSAGEPASSWARN.icon(), Icons::RESULT_MESSAGEPASSWARN.icon(),
Icons::RESULT_MESSAGEFAILWARN.icon(), Icons::RESULT_MESSAGEFAILWARN.icon(),
ProjectExplorer::Icons::DESKTOP_DEVICE.icon(), // for now
}; // provide an icon for unknown?? }; // provide an icon for unknown??
if (result < 0 || result >= Result::MessageInternal) { if (result < 0 || result >= Result::MessageInternal) {
@@ -74,6 +78,8 @@ static QIcon testResultIcon(Result::Type result) {
return icons[16]; return icons[16];
case Result::MessageTestCaseFailWarn: case Result::MessageTestCaseFailWarn:
return icons[17]; return icons[17];
case Result::Application:
return icons[18];
default: default:
return QIcon(); return QIcon();
} }
@@ -224,7 +230,32 @@ void TestResultModel::addTestResult(const TestResultPtr &testResult, bool autoEx
m_testResultCount[testResult->result()]++; m_testResultCount[testResult->result()]++;
TestResultItem *newItem = new TestResultItem(testResult); TestResultItem *newItem = new TestResultItem(testResult);
TestResultItem *parentItem = findParentItemFor(newItem);
TestResultItem *root = nullptr;
if (AutotestPlugin::settings()->displayApplication) {
const QString application = testResult->id();
if (!application.isEmpty()) {
for (int row = rootItem()->childCount() - 1; row >= 0; --row) {
TestResultItem *tmp = static_cast<TestResultItem *>(rootItem()->childAt(row));
auto tmpTestResult = tmp->testResult();
if (tmpTestResult->id() == application) {
root = tmp;
break;
}
}
if (!root) {
TestResult *tmpAppResult = new TestResult(application, application);
tmpAppResult->setResult(Result::Application);
root = new TestResultItem(TestResultPtr(tmpAppResult));
if (lastRow >= 0)
rootItem()->insertChild(lastRow, root);
else
rootItem()->appendChild(root);
}
}
}
TestResultItem *parentItem = findParentItemFor(newItem, root);
addFileName(testResult->fileName()); // ensure we calculate the results pane correctly addFileName(testResult->fileName()); // ensure we calculate the results pane correctly
if (parentItem) { if (parentItem) {
parentItem->appendChild(newItem); parentItem->appendChild(newItem);
@@ -373,7 +404,7 @@ void TestResultFilterModel::enableAllResultTypes()
<< Result::MessageTestCaseSuccess << Result::MessageTestCaseSuccessWarn << Result::MessageTestCaseSuccess << Result::MessageTestCaseSuccessWarn
<< Result::MessageTestCaseFail << Result::MessageTestCaseFailWarn << Result::MessageTestCaseFail << Result::MessageTestCaseFailWarn
<< Result::MessageTestCaseEnd << Result::MessageTestCaseEnd
<< Result::MessageInfo << Result::MessageSystem; << Result::MessageInfo << Result::MessageSystem << Result::Application;
invalidateFilter(); invalidateFilter();
} }

View File

@@ -42,6 +42,7 @@ static const char autoScrollKey[] = "AutoScrollResults";
static const char filterScanKey[] = "FilterScan"; static const char filterScanKey[] = "FilterScan";
static const char filtersKey[] = "WhiteListFilters"; static const char filtersKey[] = "WhiteListFilters";
static const char processArgsKey[] = "ProcessArgs"; static const char processArgsKey[] = "ProcessArgs";
static const char displayApplicationKey[] = "DisplayApp";
static const char groupSuffix[] = ".group"; static const char groupSuffix[] = ".group";
constexpr int defaultTimeout = 60000; constexpr int defaultTimeout = 60000;
@@ -60,6 +61,7 @@ void TestSettings::toSettings(QSettings *s) const
s->setValue(limitResultOutputKey, limitResultOutput); s->setValue(limitResultOutputKey, limitResultOutput);
s->setValue(autoScrollKey, autoScroll); s->setValue(autoScrollKey, autoScroll);
s->setValue(processArgsKey, processArgs); s->setValue(processArgsKey, processArgs);
s->setValue(displayApplicationKey, displayApplication);
s->setValue(filterScanKey, filterScan); s->setValue(filterScanKey, filterScan);
s->setValue(filtersKey, whiteListFilters); s->setValue(filtersKey, whiteListFilters);
// store frameworks and their current active and grouping state // store frameworks and their current active and grouping state
@@ -79,6 +81,7 @@ void TestSettings::fromSettings(QSettings *s)
limitResultOutput = s->value(limitResultOutputKey, true).toBool(); limitResultOutput = s->value(limitResultOutputKey, true).toBool();
autoScroll = s->value(autoScrollKey, true).toBool(); autoScroll = s->value(autoScrollKey, true).toBool();
processArgs = s->value(processArgsKey, false).toBool(); processArgs = s->value(processArgsKey, false).toBool();
displayApplication = s->value(displayApplicationKey, false).toBool();
filterScan = s->value(filterScanKey, false).toBool(); filterScan = s->value(filterScanKey, false).toBool();
whiteListFilters = s->value(filtersKey, QStringList()).toStringList(); whiteListFilters = s->value(filtersKey, QStringList()).toStringList();
// try to get settings for registered frameworks // try to get settings for registered frameworks

View File

@@ -49,6 +49,7 @@ struct TestSettings
bool autoScroll = true; bool autoScroll = true;
bool filterScan = false; bool filterScan = false;
bool processArgs = false; bool processArgs = false;
bool displayApplication = false;
QHash<Core::Id, bool> frameworks; QHash<Core::Id, bool> frameworks;
QHash<Core::Id, bool> frameworksGrouping; QHash<Core::Id, bool> frameworksGrouping;
QStringList whiteListFilters; QStringList whiteListFilters;

View File

@@ -152,6 +152,7 @@ void TestSettingsWidget::setSettings(const TestSettings &settings)
m_ui.limitResultOutputCB->setChecked(settings.limitResultOutput); m_ui.limitResultOutputCB->setChecked(settings.limitResultOutput);
m_ui.autoScrollCB->setChecked(settings.autoScroll); m_ui.autoScrollCB->setChecked(settings.autoScroll);
m_ui.processArgsCB->setChecked(settings.processArgs); m_ui.processArgsCB->setChecked(settings.processArgs);
m_ui.displayAppCB->setChecked(settings.displayApplication);
m_ui.filterGroupBox->setChecked(settings.filterScan); m_ui.filterGroupBox->setChecked(settings.filterScan);
populateFrameworksListWidget(settings.frameworks); populateFrameworksListWidget(settings.frameworks);
populateFiltersWidget(settings.whiteListFilters); populateFiltersWidget(settings.whiteListFilters);
@@ -166,6 +167,7 @@ TestSettings TestSettingsWidget::settings() const
result.limitResultOutput = m_ui.limitResultOutputCB->isChecked(); result.limitResultOutput = m_ui.limitResultOutputCB->isChecked();
result.autoScroll = m_ui.autoScrollCB->isChecked(); result.autoScroll = m_ui.autoScrollCB->isChecked();
result.processArgs = m_ui.processArgsCB->isChecked(); result.processArgs = m_ui.processArgsCB->isChecked();
result.displayApplication = m_ui.displayAppCB->isChecked();
result.filterScan = m_ui.filterGroupBox->isChecked(); result.filterScan = m_ui.filterGroupBox->isChecked();
frameworkSettings(result); frameworkSettings(result);
result.whiteListFilters = filters(); result.whiteListFilters = filters();

View File

@@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>585</width> <width>585</width>
<height>431</height> <height>458</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -73,6 +73,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="displayAppCB">
<property name="text">
<string>Group results by application</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="processArgsCB"> <widget class="QCheckBox" name="processArgsCB">
<property name="toolTip"> <property name="toolTip">

View File

@@ -210,36 +210,6 @@ bool isDiagnosticAtLocation(const ClangBackEnd::DiagnosticContainer &diagnostic,
return isDiagnosticRelatedToLocation(diagnostic, {cursorRange}, line, column); return isDiagnosticRelatedToLocation(diagnostic, {cursorRange}, line, column);
} }
QVector<ClangBackEnd::DiagnosticContainer>
filteredDiagnosticsAtLocation(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
uint line,
uint column,
QTextDocument *textDocument)
{
QVector<ClangBackEnd::DiagnosticContainer> filteredDiagnostics;
foreach (const auto &diagnostic, diagnostics) {
if (isDiagnosticAtLocation(diagnostic, line, column, textDocument))
filteredDiagnostics.append(diagnostic);
}
return filteredDiagnostics;
}
bool editorDocumentProcessorHasDiagnosticAt(
const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
uint line,
uint column,
QTextDocument *textDocument)
{
foreach (const auto &diagnostic, diagnostics) {
if (isDiagnosticAtLocation(diagnostic, line, column, textDocument))
return true;
}
return false;
}
QTextCursor cursorAtLastPositionOfLine(QTextDocument *textDocument, int lineNumber) QTextCursor cursorAtLastPositionOfLine(QTextDocument *textDocument, int lineNumber)
{ {
const QTextBlock textBlock = textDocument->findBlockByNumber(lineNumber - 1); const QTextBlock textBlock = textDocument->findBlockByNumber(lineNumber - 1);
@@ -399,24 +369,16 @@ TextEditor::RefactorMarkers ClangDiagnosticManager::takeFixItAvailableMarkers()
return fixItAvailableMarkers; return fixItAvailableMarkers;
} }
bool ClangDiagnosticManager::hasDiagnosticsAt(uint line, uint column) const TextEditor::TextMarks ClangDiagnosticManager::diagnosticTextMarksAt(uint line, uint column) const
{ {
QTextDocument *textDocument = m_textDocument->document(); QList<TextEditor::TextMark *> textMarks;
return editorDocumentProcessorHasDiagnosticAt(m_errorDiagnostics, line, column, textDocument) for (ClangTextMark *textMark : m_clangTextMarks) {
|| editorDocumentProcessorHasDiagnosticAt(m_warningDiagnostics, line, column, textDocument); if (isDiagnosticAtLocation(textMark->diagnostic(), line, column, m_textDocument->document()))
} textMarks << textMark;
}
QVector<ClangBackEnd::DiagnosticContainer> return textMarks;
ClangDiagnosticManager::diagnosticsAt(uint line, uint column) const
{
QTextDocument *textDocument = m_textDocument->document();
QVector<ClangBackEnd::DiagnosticContainer> diagnostics;
diagnostics += filteredDiagnosticsAtLocation(m_errorDiagnostics, line, column, textDocument);
diagnostics += filteredDiagnosticsAtLocation(m_warningDiagnostics, line, column, textDocument);
return diagnostics;
} }
void ClangDiagnosticManager::invalidateDiagnostics() void ClangDiagnosticManager::invalidateDiagnostics()

View File

@@ -57,8 +57,7 @@ public:
QList<QTextEdit::ExtraSelection> takeExtraSelections(); QList<QTextEdit::ExtraSelection> takeExtraSelections();
TextEditor::RefactorMarkers takeFixItAvailableMarkers(); TextEditor::RefactorMarkers takeFixItAvailableMarkers();
bool hasDiagnosticsAt(uint line, uint column) const; QList<TextEditor::TextMark *> diagnosticTextMarksAt(uint line, uint column) const;
QVector<ClangBackEnd::DiagnosticContainer> diagnosticsAt(uint line, uint column) const;
void invalidateDiagnostics(); void invalidateDiagnostics();
void clearDiagnosticsWithFixIts(); void clearDiagnosticsWithFixIts();

View File

@@ -25,6 +25,7 @@
#include "clangdiagnostictooltipwidget.h" #include "clangdiagnostictooltipwidget.h"
#include "clangfixitoperation.h" #include "clangfixitoperation.h"
#include "clangutils.h"
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
@@ -149,7 +150,7 @@ public:
QTC_CHECK(!"Link target cannot be handled."); QTC_CHECK(!"Link target cannot be handled.");
if (hideToolTipAfterLinkActivation) if (hideToolTipAfterLinkActivation)
Utils::ToolTip::hideImmediately(); ::Utils::ToolTip::hideImmediately();
}); });
return label; return label;
@@ -171,50 +172,6 @@ public:
private: private:
enum class IndentMode { Indent, DoNotIndent }; enum class IndentMode { Indent, DoNotIndent };
static bool isClazyOption(const QString &option) { return option.startsWith("-Wclazy"); }
class DiagnosticTextInfo
{
public:
DiagnosticTextInfo(const QString &text)
: m_text(text)
, m_squareBracketStartIndex(text.lastIndexOf('['))
{}
QString textWithoutOption() const
{
if (m_squareBracketStartIndex == -1)
return m_text;
return m_text.mid(0, m_squareBracketStartIndex - 1);
}
QString option() const
{
if (m_squareBracketStartIndex == -1)
return QString();
const int index = m_squareBracketStartIndex + 1;
return m_text.mid(index, m_text.count() - index - 1);
}
QString category() const
{
if (m_squareBracketStartIndex == -1)
return QString();
const int index = m_squareBracketStartIndex + 1;
if (isClazyOption(m_text.mid(index)))
return QCoreApplication::translate("ClangDiagnosticWidget", "Clazy Issue");
else
return QCoreApplication::translate("ClangDiagnosticWidget", "Clang-Tidy Issue");
}
private:
const QString m_text;
const int m_squareBracketStartIndex;
};
// Diagnostics from clazy/tidy do not have any category or option set but // Diagnostics from clazy/tidy do not have any category or option set but
// we will conclude them from the diagnostic message. // we will conclude them from the diagnostic message.
// //
@@ -233,6 +190,7 @@ private:
ClangBackEnd::DiagnosticContainer supplementedDiagnostic = diagnostic; ClangBackEnd::DiagnosticContainer supplementedDiagnostic = diagnostic;
using namespace ClangCodeModel::Utils;
DiagnosticTextInfo info(diagnostic.text); DiagnosticTextInfo info(diagnostic.text);
supplementedDiagnostic.enableOption = info.option(); supplementedDiagnostic.enableOption = info.option();
supplementedDiagnostic.category = info.category(); supplementedDiagnostic.category = info.category();
@@ -269,7 +227,7 @@ private:
QString option = optionAsUtf8String.toString(); QString option = optionAsUtf8String.toString();
// Clazy // Clazy
if (isClazyOption(option)) { if (ClangCodeModel::Utils::DiagnosticTextInfo::isClazyOption(option)) {
option = optionAsUtf8String.mid(8); // Remove "-Wclazy-" prefix. option = optionAsUtf8String.mid(8); // Remove "-Wclazy-" prefix.
return QString::fromUtf8(CLAZY_DOCUMENTATION_URL_TEMPLATE).arg(option); return QString::fromUtf8(CLAZY_DOCUMENTATION_URL_TEMPLATE).arg(option);
} }

View File

@@ -48,7 +48,6 @@
#include <cpptools/cppworkingcopy.h> #include <cpptools/cppworkingcopy.h>
#include <cpptools/editordocumenthandle.h> #include <cpptools/editordocumenthandle.h>
#include <texteditor/displaysettings.h>
#include <texteditor/fontsettings.h> #include <texteditor/fontsettings.h>
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
#include <texteditor/texteditorconstants.h> #include <texteditor/texteditorconstants.h>
@@ -292,27 +291,6 @@ TextEditor::QuickFixOperations ClangEditorDocumentProcessor::extraRefactoringOpe
return extractor.extract(assistInterface.fileName(), currentLine(assistInterface)); return extractor.extract(assistInterface.fileName(), currentLine(assistInterface));
} }
bool ClangEditorDocumentProcessor::hasDiagnosticsAt(uint line, uint column) const
{
return m_diagnosticManager.hasDiagnosticsAt(line, column);
}
void ClangEditorDocumentProcessor::addDiagnosticToolTipToLayout(uint line,
uint column,
QLayout *target) const
{
using Internal::ClangDiagnosticWidget;
const QVector<ClangBackEnd::DiagnosticContainer> diagnostics
= m_diagnosticManager.diagnosticsAt(line, column);
target->addWidget(
ClangDiagnosticWidget::createWidget(diagnostics, ClangDiagnosticWidget::ToolTip));
auto link = TextEditor::DisplaySettings::createAnnotationSettingsLink();
target->addWidget(link);
target->setAlignment(link, Qt::AlignRight);
}
void ClangEditorDocumentProcessor::editorDocumentTimerRestarted() void ClangEditorDocumentProcessor::editorDocumentTimerRestarted()
{ {
m_updateBackendDocumentTimer.stop(); // Wait for the next call to run(). m_updateBackendDocumentTimer.stop(); // Wait for the next call to run().
@@ -323,6 +301,12 @@ void ClangEditorDocumentProcessor::invalidateDiagnostics()
m_diagnosticManager.invalidateDiagnostics(); m_diagnosticManager.invalidateDiagnostics();
} }
TextEditor::TextMarks ClangEditorDocumentProcessor::diagnosticTextMarksAt(uint line,
uint column) const
{
return m_diagnosticManager.diagnosticTextMarksAt(line, column);
}
void ClangEditorDocumentProcessor::setParserConfig( void ClangEditorDocumentProcessor::setParserConfig(
const CppTools::BaseEditorDocumentParser::Configuration &config) const CppTools::BaseEditorDocumentParser::Configuration &config)
{ {
@@ -468,6 +452,10 @@ public:
const QStringList &options() const { return m_options; } const QStringList &options() const { return m_options; }
const Core::Id &diagnosticConfigId() const { return m_diagnosticConfigId; } const Core::Id &diagnosticConfigId() const { return m_diagnosticConfigId; }
CppTools::UseBuildSystemWarnings useBuildSystemWarnings() const
{
return m_useBuildSystemWarnings;
}
private: private:
void addLanguageOptions() void addLanguageOptions()
@@ -507,6 +495,9 @@ private:
void addDiagnosticOptionsForConfig(const CppTools::ClangDiagnosticConfig &diagnosticConfig) void addDiagnosticOptionsForConfig(const CppTools::ClangDiagnosticConfig &diagnosticConfig)
{ {
m_diagnosticConfigId = diagnosticConfig.id(); m_diagnosticConfigId = diagnosticConfig.id();
m_useBuildSystemWarnings = diagnosticConfig.useBuildSystemWarnings()
? CppTools::UseBuildSystemWarnings::Yes
: CppTools::UseBuildSystemWarnings::No;
m_options.append(diagnosticConfig.clangOptions()); m_options.append(diagnosticConfig.clangOptions());
addClangTidyOptions(diagnosticConfig); addClangTidyOptions(diagnosticConfig);
@@ -581,6 +572,7 @@ private:
const CppTools::ProjectPart &m_projectPart; const CppTools::ProjectPart &m_projectPart;
Core::Id m_diagnosticConfigId; Core::Id m_diagnosticConfigId;
CppTools::UseBuildSystemWarnings m_useBuildSystemWarnings = CppTools::UseBuildSystemWarnings::No;
CppTools::CompilerOptionsBuilder m_builder; CppTools::CompilerOptionsBuilder m_builder;
QStringList m_options; QStringList m_options;
}; };
@@ -602,13 +594,13 @@ void ClangEditorDocumentProcessor::updateBackendDocument(CppTools::ProjectPart &
return; return;
} }
const QStringList projectPartOptions = ClangCodeModel::Utils::createClangOptions(
projectPart,
CppTools::ProjectFile::Unsupported); // No language option as FileOptionsBuilder adds it.
const FileOptionsBuilder fileOptions(filePath(), projectPart); const FileOptionsBuilder fileOptions(filePath(), projectPart);
m_diagnosticConfigId = fileOptions.diagnosticConfigId(); m_diagnosticConfigId = fileOptions.diagnosticConfigId();
const QStringList projectPartOptions = ClangCodeModel::Utils::createClangOptions(
projectPart, fileOptions.useBuildSystemWarnings(),
CppTools::ProjectFile::Unsupported); // No language option as FileOptionsBuilder adds it.
const QStringList compilationArguments = projectPartOptions + fileOptions.options(); const QStringList compilationArguments = projectPartOptions + fileOptions.options();
m_communicator.documentsOpened( m_communicator.documentsOpened(

View File

@@ -83,8 +83,8 @@ public:
extraRefactoringOperations(const TextEditor::AssistInterface &assistInterface) override; extraRefactoringOperations(const TextEditor::AssistInterface &assistInterface) override;
void invalidateDiagnostics() override; void invalidateDiagnostics() override;
bool hasDiagnosticsAt(uint line, uint column) const override;
void addDiagnosticToolTipToLayout(uint line, uint column, QLayout *target) const override; TextEditor::TextMarks diagnosticTextMarksAt(uint line, uint column) const;
void editorDocumentTimerRestarted() override; void editorDocumentTimerRestarted() override;

View File

@@ -25,8 +25,9 @@
#include "clanghoverhandler.h" #include "clanghoverhandler.h"
#include "clangeditordocumentprocessor.h"
#include <coreplugin/helpmanager.h> #include <coreplugin/helpmanager.h>
#include <cpptools/baseeditordocumentprocessor.h>
#include <cpptools/cppmodelmanager.h> #include <cpptools/cppmodelmanager.h>
#include <cpptools/cpptoolsreuse.h> #include <cpptools/cpptoolsreuse.h>
#include <cpptools/editordocumenthandle.h> #include <cpptools/editordocumenthandle.h>
@@ -61,32 +62,17 @@ static CppTools::BaseEditorDocumentProcessor *editorDocumentProcessor(TextEditor
return nullptr; return nullptr;
} }
static bool editorDocumentProcessorHasDiagnosticAt(TextEditorWidget *editorWidget, int pos) static TextMarks diagnosticTextMarksAt(TextEditorWidget *editorWidget, int position)
{ {
if (CppTools::BaseEditorDocumentProcessor *processor = editorDocumentProcessor(editorWidget)) { const auto processor = qobject_cast<ClangEditorDocumentProcessor *>(
int line, column; editorDocumentProcessor(editorWidget));
if (Utils::Text::convertPosition(editorWidget->document(), pos, &line, &column)) QTC_ASSERT(processor, return TextMarks());
return processor->hasDiagnosticsAt(line, column);
}
return false; int line, column;
} const bool ok = Utils::Text::convertPosition(editorWidget->document(), position, &line, &column);
QTC_ASSERT(ok, return TextMarks());
static void processWithEditorDocumentProcessor(TextEditorWidget *editorWidget, return processor->diagnosticTextMarksAt(line, column);
const QPoint &point,
int position,
const Core::HelpItem &helpItem)
{
if (CppTools::BaseEditorDocumentProcessor *processor = editorDocumentProcessor(editorWidget)) {
int line, column;
if (Utils::Text::convertPosition(editorWidget->document(), position, &line, &column)) {
auto layout = new QVBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(2);
processor->addDiagnosticToolTipToLayout(line, column, layout);
Utils::ToolTip::show(point, layout, editorWidget, qVariantFromValue(helpItem));
}
}
} }
static QFuture<CppTools::ToolTipInfo> editorDocumentHandlesToolTipInfo( static QFuture<CppTools::ToolTipInfo> editorDocumentHandlesToolTipInfo(
@@ -189,7 +175,7 @@ void ClangHoverHandler::identifyMatch(TextEditorWidget *editorWidget,
m_cursorPosition = -1; m_cursorPosition = -1;
// Check for diagnostics (sync) // Check for diagnostics (sync)
if (!isContextHelpRequest() && editorDocumentProcessorHasDiagnosticAt(editorWidget, pos)) { if (!isContextHelpRequest() && !diagnosticTextMarksAt(editorWidget, pos).isEmpty()) {
qCDebug(hoverLog) << "Checking for diagnostic at" << pos; qCDebug(hoverLog) << "Checking for diagnostic at" << pos;
setPriority(Priority_Diagnostic); setPriority(Priority_Diagnostic);
m_cursorPosition = pos; m_cursorPosition = pos;
@@ -275,10 +261,8 @@ void ClangHoverHandler::operateTooltip(TextEditor::TextEditorWidget *editorWidge
const QPoint &point) const QPoint &point)
{ {
if (priority() == Priority_Diagnostic) { if (priority() == Priority_Diagnostic) {
processWithEditorDocumentProcessor(editorWidget, const TextMarks textMarks = diagnosticTextMarksAt(editorWidget, m_cursorPosition);
point, editorWidget->showTextMarksToolTip(point, textMarks);
m_cursorPosition,
lastHelpItemIdentified());
return; return;
} }

View File

@@ -27,11 +27,20 @@
#include "clangconstants.h" #include "clangconstants.h"
#include "clangdiagnostictooltipwidget.h" #include "clangdiagnostictooltipwidget.h"
#include "clangeditordocumentprocessor.h"
#include "clangmodelmanagersupport.h"
#include "clangprojectsettings.h"
#include "clangutils.h" #include "clangutils.h"
#include <utils/utilsicons.h> #include <coreplugin/icore.h>
#include <cpptools/clangdiagnosticconfigsmodel.h>
#include <cpptools/cpptoolsreuse.h>
#include <cpptools/cppcodemodelsettings.h>
#include <utils/fadingindicator.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/theme/theme.h> #include <utils/theme/theme.h>
#include <utils/utilsicons.h>
#include <QAction> #include <QAction>
#include <QApplication> #include <QApplication>
@@ -64,6 +73,102 @@ static Core::Id categoryForSeverity(ClangBackEnd::DiagnosticSeverity severity)
return isWarningOrNote(severity) ? Constants::CLANG_WARNING : Constants::CLANG_ERROR; return isWarningOrNote(severity) ? Constants::CLANG_WARNING : Constants::CLANG_ERROR;
} }
ProjectExplorer::Project *projectForCurrentEditor()
{
using namespace CppTools;
using namespace ClangCodeModel::Internal;
const QString filePath = Utils::currentCppEditorDocumentFilePath();
if (filePath.isEmpty())
return nullptr;
if (auto processor = ClangEditorDocumentProcessor::get(filePath)) {
if (ProjectPart::Ptr projectPart = processor->projectPart())
return projectPart->project;
}
return nullptr;
}
void disableDiagnosticInConfig(CppTools::ClangDiagnosticConfig &config,
const ClangBackEnd::DiagnosticContainer &diagnostic)
{
// Clang check
if (!diagnostic.disableOption.isEmpty()) {
config.setClangOptions(config.clangOptions() + QStringList(diagnostic.disableOption));
return;
}
// Clazy check
using namespace ClangCodeModel::Utils;
DiagnosticTextInfo textInfo(diagnostic.text);
if (DiagnosticTextInfo::isClazyOption(textInfo.option())) {
const QString checkName = DiagnosticTextInfo::clazyCheckName(textInfo.option());
QStringList newChecks = config.clazyChecks().split(',');
newChecks.removeOne(checkName);
config.setClazyChecks(newChecks.join(','));
return;
}
// Tidy check
config.setClangTidyChecks(config.clangTidyChecks() + QString(",-") + textInfo.option());
}
void disableDiagnosticInCurrentProjectConfig(const ClangBackEnd::DiagnosticContainer &diagnostic)
{
using namespace CppTools;
using namespace ClangCodeModel::Internal;
ProjectExplorer::Project *project = projectForCurrentEditor();
QTC_ASSERT(project, return );
// Get settings
ClangProjectSettings &projectSettings = ClangModelManagerSupport::instance()->projectSettings(
project);
const QSharedPointer<CppCodeModelSettings> globalSettings = codeModelSettings();
// Get config id
Core::Id currentConfigId = projectSettings.warningConfigId();
if (projectSettings.useGlobalConfig())
currentConfigId = globalSettings->clangDiagnosticConfigId();
// Get config
const ClangDiagnosticConfigs originalConfigs = globalSettings->clangCustomDiagnosticConfigs();
ClangDiagnosticConfigsModel configsModel(globalSettings->clangCustomDiagnosticConfigs());
QTC_ASSERT(configsModel.hasConfigWithId(currentConfigId), return );
ClangDiagnosticConfig config = configsModel.configWithId(currentConfigId);
// Create copy if needed
if (config.isReadOnly()) {
const QString name = QCoreApplication::translate("ClangDiagnosticConfig",
"Project: %1 (based on %2)")
.arg(project->displayName(), config.displayName());
config = ClangDiagnosticConfigsModel::createCustomConfig(config, name);
}
// Modify diagnostic config
disableDiagnosticInConfig(config, diagnostic);
configsModel.appendOrUpdate(config);
// Set global settings
globalSettings->setClangCustomDiagnosticConfigs(configsModel.customConfigs());
globalSettings->toSettings(Core::ICore::settings());
// Set project settings
if (projectSettings.useGlobalConfig())
projectSettings.setUseGlobalConfig(false);
projectSettings.setWarningConfigId(config.id());
projectSettings.store();
// Notify the user about changed project specific settings
const QString text
= QCoreApplication::translate("ClangDiagnosticConfig",
"Changes applied in Projects Mode > Clang Code Model");
::Utils::FadingIndicator::showText(Core::ICore::mainWindow(),
text,
::Utils::FadingIndicator::SmallText);
}
} // anonymous namespace } // anonymous namespace
ClangTextMark::ClangTextMark(const FileName &fileName, ClangTextMark::ClangTextMark(const FileName &fileName,
@@ -88,6 +193,8 @@ ClangTextMark::ClangTextMark(const FileName &fileName,
: ::Utils::Theme::CodeModel_Error_TextMarkColor); : ::Utils::Theme::CodeModel_Error_TextMarkColor);
} }
// Copy to clipboard action
QVector<QAction *> actions;
QAction *action = new QAction(); QAction *action = new QAction();
action->setIcon(QIcon::fromTheme("edit-copy", ::Utils::Icons::COPY.icon())); action->setIcon(QIcon::fromTheme("edit-copy", ::Utils::Icons::COPY.icon()));
QObject::connect(action, &QAction::triggered, [diagnostic]() { QObject::connect(action, &QAction::triggered, [diagnostic]() {
@@ -96,7 +203,19 @@ ClangTextMark::ClangTextMark(const FileName &fileName,
ClangDiagnosticWidget::InfoBar); ClangDiagnosticWidget::InfoBar);
QApplication::clipboard()->setText(text, QClipboard::Clipboard); QApplication::clipboard()->setText(text, QClipboard::Clipboard);
}); });
setActions({action}); actions << action;
// Remove diagnostic warning action
if (projectForCurrentEditor()) {
action = new QAction();
action->setIcon(::Utils::Icons::BROKEN.icon());
QObject::connect(action, &QAction::triggered, [diagnostic]() {
disableDiagnosticInCurrentProjectConfig(diagnostic);
});
actions << action;
}
setActions(actions);
} }
void ClangTextMark::updateIcon(bool valid) void ClangTextMark::updateIcon(bool valid)

View File

@@ -44,7 +44,9 @@ public:
const RemovedFromEditorHandler &removedHandler, const RemovedFromEditorHandler &removedHandler,
bool fullVisualization); bool fullVisualization);
ClangBackEnd::DiagnosticContainer diagnostic() const { return m_diagnostic; }
void updateIcon(bool valid = true); void updateIcon(bool valid = true);
private: private:
bool addToolTipContent(QLayout *target) const override; bool addToolTipContent(QLayout *target) const override;
void removedFromEditor() override; void removedFromEditor() override;

View File

@@ -66,11 +66,13 @@ namespace Utils {
class LibClangOptionsBuilder final : public CompilerOptionsBuilder class LibClangOptionsBuilder final : public CompilerOptionsBuilder
{ {
public: public:
LibClangOptionsBuilder(const ProjectPart &projectPart) LibClangOptionsBuilder(const ProjectPart &projectPart,
UseBuildSystemWarnings useBuildSystemWarnings)
: CompilerOptionsBuilder(projectPart, : CompilerOptionsBuilder(projectPart,
UseSystemHeader::No, UseSystemHeader::No,
UseTweakedHeaderPaths::Yes, UseTweakedHeaderPaths::Yes,
UseLanguageDefines::No, UseLanguageDefines::No,
useBuildSystemWarnings,
QString(CLANG_VERSION), QString(CLANG_VERSION),
QString(CLANG_RESOURCE_DIR)) QString(CLANG_RESOURCE_DIR))
{ {
@@ -101,9 +103,12 @@ private:
} }
}; };
QStringList createClangOptions(const ProjectPart &projectPart, ProjectFile::Kind fileKind) QStringList createClangOptions(const ProjectPart &projectPart,
UseBuildSystemWarnings useBuildSystemWarnings,
ProjectFile::Kind fileKind)
{ {
return LibClangOptionsBuilder(projectPart).build(fileKind, UsePrecompiledHeaders::No); return LibClangOptionsBuilder(projectPart, useBuildSystemWarnings)
.build(fileKind, UsePrecompiledHeaders::No);
} }
ProjectPart::Ptr projectPartForFile(const QString &filePath) ProjectPart::Ptr projectPartForFile(const QString &filePath)
@@ -368,5 +373,51 @@ QString currentCppEditorDocumentFilePath()
return filePath; return filePath;
} }
DiagnosticTextInfo::DiagnosticTextInfo(const QString &text)
: m_text(text)
, m_squareBracketStartIndex(text.lastIndexOf('['))
{}
QString DiagnosticTextInfo::textWithoutOption() const
{
if (m_squareBracketStartIndex == -1)
return m_text;
return m_text.mid(0, m_squareBracketStartIndex - 1);
}
QString DiagnosticTextInfo::option() const
{
if (m_squareBracketStartIndex == -1)
return QString();
const int index = m_squareBracketStartIndex + 1;
return m_text.mid(index, m_text.count() - index - 1);
}
QString DiagnosticTextInfo::category() const
{
if (m_squareBracketStartIndex == -1)
return QString();
const int index = m_squareBracketStartIndex + 1;
if (isClazyOption(m_text.mid(index)))
return QCoreApplication::translate("ClangDiagnosticWidget", "Clazy Issue");
else
return QCoreApplication::translate("ClangDiagnosticWidget", "Clang-Tidy Issue");
}
bool DiagnosticTextInfo::isClazyOption(const QString &option)
{
return option.startsWith("-Wclazy");
}
QString DiagnosticTextInfo::clazyCheckName(const QString &option)
{
if (option.startsWith("-Wclazy"))
return option.mid(8); // Chop "-Wclazy-"
return option;
}
} // namespace Utils } // namespace Utils
} // namespace Clang } // namespace Clang

View File

@@ -28,6 +28,7 @@
#include <cplusplus/Icons.h> #include <cplusplus/Icons.h>
#include <cpptools/projectpart.h> #include <cpptools/projectpart.h>
#include <cpptools/compileroptionsbuilder.h>
#include <QTextCursor> #include <QTextCursor>
@@ -53,6 +54,7 @@ CppTools::CppEditorDocumentHandle *cppDocument(const QString &filePath);
void setLastSentDocumentRevision(const QString &filePath, uint revision); void setLastSentDocumentRevision(const QString &filePath, uint revision);
QStringList createClangOptions(const CppTools::ProjectPart &projectPart, QStringList createClangOptions(const CppTools::ProjectPart &projectPart,
CppTools::UseBuildSystemWarnings useBuildSystemWarnings,
CppTools::ProjectFile::Kind fileKind); CppTools::ProjectFile::Kind fileKind);
CppTools::ProjectPart::Ptr projectPartForFile(const QString &filePath); CppTools::ProjectPart::Ptr projectPartForFile(const QString &filePath);
@@ -70,6 +72,23 @@ QString diagnosticCategoryPrefixRemoved(const QString &text);
void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo); void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo);
class DiagnosticTextInfo
{
public:
DiagnosticTextInfo(const QString &text);
QString textWithoutOption() const;
QString option() const;
QString category() const;
static bool isClazyOption(const QString &option);
static QString clazyCheckName(const QString &option);
private:
const QString m_text;
const int m_squareBracketStartIndex;
};
namespace Text { namespace Text {
template <class CharacterProvider> template <class CharacterProvider>

View File

@@ -195,6 +195,7 @@ static AnalyzeUnits toAnalyzeUnits(const FileInfos &fileInfos)
UseSystemHeader::No, UseSystemHeader::No,
UseTweakedHeaderPaths::Yes, UseTweakedHeaderPaths::Yes,
UseLanguageDefines::No, UseLanguageDefines::No,
UseBuildSystemWarnings::No,
QString(CLANG_VERSION), QString(CLANG_VERSION),
QString(CLANG_RESOURCE_DIR)); QString(CLANG_RESOURCE_DIR));
QStringList arguments = extraClangToolsPrependOptions(); QStringList arguments = extraClangToolsPrependOptions();

View File

@@ -223,7 +223,7 @@ bool PreconfiguredSessionTests::switchToProjectAndTarget(Project *project,
SessionManager::setActiveTarget(project, target, ProjectExplorer::SetActive::NoCascade); SessionManager::setActiveTarget(project, target, ProjectExplorer::SetActive::NoCascade);
QTC_ASSERT(spyFinishedParsing.wait(30000), return false); QTC_ASSERT(spyFinishedParsing.wait(30000), return false);
const QVariant projectArgument = spyFinishedParsing.takeFirst().takeFirst(); const QVariant projectArgument = spyFinishedParsing.takeFirst().constFirst();
QTC_ASSERT(projectArgument.canConvert<ProjectExplorer::Project *>(), return false); QTC_ASSERT(projectArgument.canConvert<ProjectExplorer::Project *>(), return false);
return projectArgument.value<ProjectExplorer::Project *>() == project; return projectArgument.value<ProjectExplorer::Project *>() == project;

View File

@@ -94,7 +94,7 @@ void ClangToolsUnitTests::testProject()
QFETCH(int, expectedDiagCount); QFETCH(int, expectedDiagCount);
if (projectFilePath.contains("mingw")) { if (projectFilePath.contains("mingw")) {
const ToolChain * const toolchain const ToolChain * const toolchain
= ToolChainKitInformation::toolChain(KitManager::kits().first(), = ToolChainKitInformation::toolChain(KitManager::kits().constFirst(),
Constants::CXX_LANGUAGE_ID); Constants::CXX_LANGUAGE_ID);
if (toolchain->typeId() != ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID) if (toolchain->typeId() != ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID)
QSKIP("This test is mingw specific, does not run for other toolchains"); QSKIP("This test is mingw specific, does not run for other toolchains");

View File

@@ -102,7 +102,7 @@ QT_BEGIN_NAMESPACE
namespace QTest { namespace QTest {
template<> char *toString(const OverrideItem &data) template<> char *toString(const OverrideItem &data)
{ {
return qstrdup(data.toByteArray().data()); return qstrdup(data.toByteArray().constData());
} }
} }

View File

@@ -72,15 +72,6 @@ BaseEditorDocumentProcessor::extraRefactoringOperations(const TextEditor::Assist
return TextEditor::QuickFixOperations(); return TextEditor::QuickFixOperations();
} }
bool BaseEditorDocumentProcessor::hasDiagnosticsAt(uint, uint) const
{
return false;
}
void BaseEditorDocumentProcessor::addDiagnosticToolTipToLayout(uint, uint, QLayout *) const
{
}
void BaseEditorDocumentProcessor::editorDocumentTimerRestarted() void BaseEditorDocumentProcessor::editorDocumentTimerRestarted()
{ {
} }

View File

@@ -81,8 +81,6 @@ public:
extraRefactoringOperations(const TextEditor::AssistInterface &assistInterface); extraRefactoringOperations(const TextEditor::AssistInterface &assistInterface);
virtual void invalidateDiagnostics(); virtual void invalidateDiagnostics();
virtual bool hasDiagnosticsAt(uint line, uint column) const;
virtual void addDiagnosticToolTipToLayout(uint line, uint column, QLayout *layout) const;
virtual void editorDocumentTimerRestarted(); virtual void editorDocumentTimerRestarted();

View File

@@ -24,6 +24,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="useFlagsFromBuildSystemCheckBox">
<property name="text">
<string>Use diagnostic flags from build system</string>
</property>
</widget>
</item>
<item> <item>
<widget class="CppTools::WrappableLineEdit" name="diagnosticOptionsTextEdit"/> <widget class="CppTools::WrappableLineEdit" name="diagnosticOptionsTextEdit"/>
</item> </item>

View File

@@ -75,7 +75,8 @@ bool ClangDiagnosticConfig::operator==(const ClangDiagnosticConfig &other) const
&& m_clangTidyMode == other.m_clangTidyMode && m_clangTidyMode == other.m_clangTidyMode
&& m_clangTidyChecks == other.m_clangTidyChecks && m_clangTidyChecks == other.m_clangTidyChecks
&& m_clazyChecks == other.m_clazyChecks && m_clazyChecks == other.m_clazyChecks
&& m_isReadOnly == other.m_isReadOnly; && m_isReadOnly == other.m_isReadOnly
&& m_useBuildSystemWarnings == other.m_useBuildSystemWarnings;
} }
bool ClangDiagnosticConfig::operator!=(const ClangDiagnosticConfig &other) const bool ClangDiagnosticConfig::operator!=(const ClangDiagnosticConfig &other) const
@@ -83,6 +84,16 @@ bool ClangDiagnosticConfig::operator!=(const ClangDiagnosticConfig &other) const
return !(*this == other); return !(*this == other);
} }
bool ClangDiagnosticConfig::useBuildSystemWarnings() const
{
return m_useBuildSystemWarnings;
}
void ClangDiagnosticConfig::setUseBuildSystemWarnings(bool useBuildSystemWarnings)
{
m_useBuildSystemWarnings = useBuildSystemWarnings;
}
ClangDiagnosticConfig::TidyMode ClangDiagnosticConfig::clangTidyMode() const ClangDiagnosticConfig::TidyMode ClangDiagnosticConfig::clangTidyMode() const
{ {
return m_clangTidyMode; return m_clangTidyMode;

View File

@@ -65,6 +65,9 @@ public:
bool isReadOnly() const; bool isReadOnly() const;
void setIsReadOnly(bool isReadOnly); void setIsReadOnly(bool isReadOnly);
bool useBuildSystemWarnings() const;
void setUseBuildSystemWarnings(bool useBuildSystemWarnings);
bool operator==(const ClangDiagnosticConfig &other) const; bool operator==(const ClangDiagnosticConfig &other) const;
bool operator!=(const ClangDiagnosticConfig &other) const; bool operator!=(const ClangDiagnosticConfig &other) const;
@@ -76,6 +79,7 @@ private:
QString m_clangTidyChecks; QString m_clangTidyChecks;
QString m_clazyChecks; QString m_clazyChecks;
bool m_isReadOnly = false; bool m_isReadOnly = false;
bool m_useBuildSystemWarnings = false;
}; };
using ClangDiagnosticConfigs = QVector<ClangDiagnosticConfig>; using ClangDiagnosticConfigs = QVector<ClangDiagnosticConfig>;

View File

@@ -25,6 +25,7 @@
#include "clangdiagnosticconfigsmodel.h" #include "clangdiagnosticconfigsmodel.h"
#include "cpptoolsreuse.h"
#include "cpptoolsconstants.h" #include "cpptoolsconstants.h"
#include <utils/algorithm.h> #include <utils/algorithm.h>
@@ -73,7 +74,6 @@ constexpr const char *DEFAULT_TIDY_CHECKS = "-*,"
"-readability-braces-around-statements," "-readability-braces-around-statements,"
"-readability-implicit-bool-conversion," "-readability-implicit-bool-conversion,"
"-readability-named-parameter"; "-readability-named-parameter";
constexpr const char *DEFAULT_CLAZY_CHECKS = "level0";
static void addConfigForAlmostEveryWarning(ClangDiagnosticConfigsModel &model) static void addConfigForAlmostEveryWarning(ClangDiagnosticConfigsModel &model)
{ {
@@ -141,7 +141,7 @@ static void addConfigForClazy(ClangDiagnosticConfigsModel &model)
"Clazy level0 checks")); "Clazy level0 checks"));
config.setIsReadOnly(true); config.setIsReadOnly(true);
config.setClangOptions(QStringList{QStringLiteral("-w")}); config.setClangOptions(QStringList{QStringLiteral("-w")});
config.setClazyChecks(QString::fromUtf8(DEFAULT_CLAZY_CHECKS)); config.setClazyChecks(clazyChecksForLevel(0));
model.appendOrUpdate(config); model.appendOrUpdate(config);
} }
@@ -157,7 +157,19 @@ static void addConfigForTidyAndClazy(ClangDiagnosticConfigsModel &model)
config.setClangTidyMode(ClangDiagnosticConfig::TidyMode::ChecksPrefixList); config.setClangTidyMode(ClangDiagnosticConfig::TidyMode::ChecksPrefixList);
config.setClangTidyChecks(QString::fromUtf8(DEFAULT_TIDY_CHECKS)); config.setClangTidyChecks(QString::fromUtf8(DEFAULT_TIDY_CHECKS));
config.setClazyChecks(QString::fromUtf8(DEFAULT_CLAZY_CHECKS)); config.setClazyChecks(clazyChecksForLevel(0));
model.appendOrUpdate(config);
}
static void addConfigForBuildSystem(ClangDiagnosticConfigsModel &model)
{
ClangDiagnosticConfig config;
config.setId("Builtin.BuildSystem");
config.setDisplayName(QCoreApplication::translate("ClangDiagnosticConfigsModel",
"Build-systems' warnings"));
config.setIsReadOnly(true);
config.setUseBuildSystemWarnings(true);
model.appendOrUpdate(config); model.appendOrUpdate(config);
} }
@@ -171,6 +183,7 @@ static void addBuiltinConfigs(ClangDiagnosticConfigsModel &model)
addConfigForClangAnalyze(model); addConfigForClangAnalyze(model);
addConfigForClazy(model); addConfigForClazy(model);
addConfigForTidyAndClazy(model); addConfigForTidyAndClazy(model);
addConfigForBuildSystem(model);
} }
ClangDiagnosticConfigsModel::ClangDiagnosticConfigsModel(const ClangDiagnosticConfigs &customConfigs) ClangDiagnosticConfigsModel::ClangDiagnosticConfigsModel(const ClangDiagnosticConfigs &customConfigs)

View File

@@ -38,6 +38,7 @@
#include <projectexplorer/selectablefilesmodel.h> #include <projectexplorer/selectablefilesmodel.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/executeondestruction.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
@@ -318,16 +319,6 @@ public:
m_root->checked = Qt::Unchecked; m_root->checked = Qt::Unchecked;
propagateDown(index(0, 0, QModelIndex())); propagateDown(index(0, 0, QModelIndex()));
// <= Qt Creator 4.8 settings provide specific levels: {"level0"}
if (checks.size() == 1 && checks.first().startsWith("level")) {
bool ok = false;
const int level = checks.first().mid(5).toInt(&ok);
QTC_ASSERT(ok, return);
enableChecksByLevel(level);
return;
}
// >= Qt Creator 4.9 settings provide specific checks: {c1, c2, ...}
for (const QString &check : checks) { for (const QString &check : checks) {
const QModelIndex index = indexForCheck(check); const QModelIndex index = indexForCheck(check);
if (!index.isValid()) if (!index.isValid())
@@ -436,23 +427,6 @@ private:
} }
} }
void enableChecksByLevel(int level)
{
if (level < 0)
return;
ClazyChecksTree *node = m_levelNodes.value(level);
QTC_ASSERT(node, return);
const QModelIndex index = indexForTree(node);
QTC_ASSERT(index.isValid(), return);
node->checked = Qt::Checked;
propagateUp(index);
propagateDown(index);
enableChecksByLevel(--level);
}
QModelIndex indexForCheck(const QString &check) const { QModelIndex indexForCheck(const QString &check) const {
if (check == "*") if (check == "*")
return index(0, 0, QModelIndex()); return index(0, 0, QModelIndex());
@@ -536,7 +510,7 @@ public:
const auto *node = ClazyChecksTree::fromIndex(index); const auto *node = ClazyChecksTree::fromIndex(index);
if (node->kind == ClazyChecksTree::CheckNode) { if (node->kind == ClazyChecksTree::CheckNode) {
const QStringList topics = node->checkInfo.topics; const QStringList topics = node->checkInfo.topics;
return Utils::anyOf(m_topics, [this, topics](const QString &topic) { return Utils::anyOf(m_topics, [topics](const QString &topic) {
return topics.contains(topic); return topics.contains(topic);
}); });
} }
@@ -611,7 +585,7 @@ ClangDiagnosticConfigsWidget::ClangDiagnosticConfigsWidget(const Core::Id &confi
this, &ClangDiagnosticConfigsWidget::onCopyButtonClicked); this, &ClangDiagnosticConfigsWidget::onCopyButtonClicked);
connect(m_ui->removeButton, &QPushButton::clicked, connect(m_ui->removeButton, &QPushButton::clicked,
this, &ClangDiagnosticConfigsWidget::onRemoveButtonClicked); this, &ClangDiagnosticConfigsWidget::onRemoveButtonClicked);
connectDiagnosticOptionsChanged(); connectClangOnlyOptionsChanged();
connect(m_tidyChecks->checksPrefixesTree, connect(m_tidyChecks->checksPrefixesTree,
&QTreeView::clicked, &QTreeView::clicked,
@@ -734,14 +708,17 @@ static QStringList normalizeDiagnosticInputOptions(const QString &options)
return options.simplified().split(QLatin1Char(' '), QString::SkipEmptyParts); return options.simplified().split(QLatin1Char(' '), QString::SkipEmptyParts);
} }
void ClangDiagnosticConfigsWidget::onDiagnosticOptionsEdited() void ClangDiagnosticConfigsWidget::onClangOnlyOptionsChanged()
{ {
// Clean up input const bool useBuildSystemWarnings = m_clangBaseChecks->useFlagsFromBuildSystemCheckBox
->isChecked();
// Clean up options input
const QString diagnosticOptions = m_clangBaseChecks->diagnosticOptionsTextEdit->document() const QString diagnosticOptions = m_clangBaseChecks->diagnosticOptionsTextEdit->document()
->toPlainText(); ->toPlainText();
const QStringList normalizedOptions = normalizeDiagnosticInputOptions(diagnosticOptions); const QStringList normalizedOptions = normalizeDiagnosticInputOptions(diagnosticOptions);
// Validate // Validate options input
const QString errorMessage = validateDiagnosticOptions(normalizedOptions); const QString errorMessage = validateDiagnosticOptions(normalizedOptions);
updateValidityWidgets(errorMessage); updateValidityWidgets(errorMessage);
if (!errorMessage.isEmpty()) { if (!errorMessage.isEmpty()) {
@@ -754,6 +731,7 @@ void ClangDiagnosticConfigsWidget::onDiagnosticOptionsEdited()
// Commit valid changes // Commit valid changes
ClangDiagnosticConfig updatedConfig = selectedConfig(); ClangDiagnosticConfig updatedConfig = selectedConfig();
updatedConfig.setClangOptions(normalizedOptions); updatedConfig.setClangOptions(normalizedOptions);
updatedConfig.setUseBuildSystemWarnings(useBuildSystemWarnings);
updateConfig(updatedConfig); updateConfig(updatedConfig);
} }
@@ -793,11 +771,17 @@ void ClangDiagnosticConfigsWidget::syncOtherWidgetsToComboBox()
if (isConfigChooserEmpty()) if (isConfigChooserEmpty())
return; return;
disconnectClangOnlyOptionsChanged();
Utils::ExecuteOnDestruction e([this]() { connectClangOnlyOptionsChanged(); });
const ClangDiagnosticConfig &config = selectedConfig(); const ClangDiagnosticConfig &config = selectedConfig();
// Update main button row // Update main button row
m_ui->removeButton->setEnabled(!config.isReadOnly()); m_ui->removeButton->setEnabled(!config.isReadOnly());
// Update check box
m_clangBaseChecks->useFlagsFromBuildSystemCheckBox->setChecked(config.useBuildSystemWarnings());
// Update Text Edit // Update Text Edit
const QString options = m_notAcceptedOptions.contains(config.id()) const QString options = m_notAcceptedOptions.contains(config.id())
? m_notAcceptedOptions.value(config.id()) ? m_notAcceptedOptions.value(config.id())
@@ -894,11 +878,8 @@ bool ClangDiagnosticConfigsWidget::isConfigChooserEmpty() const
void ClangDiagnosticConfigsWidget::setDiagnosticOptions(const QString &options) void ClangDiagnosticConfigsWidget::setDiagnosticOptions(const QString &options)
{ {
if (options != m_clangBaseChecks->diagnosticOptionsTextEdit->document()->toPlainText()) { if (options != m_clangBaseChecks->diagnosticOptionsTextEdit->document()->toPlainText())
disconnectDiagnosticOptionsChanged();
m_clangBaseChecks->diagnosticOptionsTextEdit->document()->setPlainText(options); m_clangBaseChecks->diagnosticOptionsTextEdit->document()->setPlainText(options);
connectDiagnosticOptionsChanged();
}
const QString errorMessage const QString errorMessage
= validateDiagnosticOptions(normalizeDiagnosticInputOptions(options)); = validateDiagnosticOptions(normalizeDiagnosticInputOptions(options));
@@ -968,20 +949,28 @@ void ClangDiagnosticConfigsWidget::disconnectConfigChooserCurrentIndex()
this, &ClangDiagnosticConfigsWidget::onCurrentConfigChanged); this, &ClangDiagnosticConfigsWidget::onCurrentConfigChanged);
} }
void ClangDiagnosticConfigsWidget::connectDiagnosticOptionsChanged() void ClangDiagnosticConfigsWidget::connectClangOnlyOptionsChanged()
{ {
connect(m_clangBaseChecks->useFlagsFromBuildSystemCheckBox,
&QCheckBox::stateChanged,
this,
&ClangDiagnosticConfigsWidget::onClangOnlyOptionsChanged);
connect(m_clangBaseChecks->diagnosticOptionsTextEdit->document(), connect(m_clangBaseChecks->diagnosticOptionsTextEdit->document(),
&QTextDocument::contentsChanged, &QTextDocument::contentsChanged,
this, this,
&ClangDiagnosticConfigsWidget::onDiagnosticOptionsEdited); &ClangDiagnosticConfigsWidget::onClangOnlyOptionsChanged);
} }
void ClangDiagnosticConfigsWidget::disconnectDiagnosticOptionsChanged() void ClangDiagnosticConfigsWidget::disconnectClangOnlyOptionsChanged()
{ {
disconnect(m_clangBaseChecks->useFlagsFromBuildSystemCheckBox,
&QCheckBox::stateChanged,
this,
&ClangDiagnosticConfigsWidget::onClangOnlyOptionsChanged);
disconnect(m_clangBaseChecks->diagnosticOptionsTextEdit->document(), disconnect(m_clangBaseChecks->diagnosticOptionsTextEdit->document(),
&QTextDocument::contentsChanged, &QTextDocument::contentsChanged,
this, this,
&ClangDiagnosticConfigsWidget::onDiagnosticOptionsEdited); &ClangDiagnosticConfigsWidget::onClangOnlyOptionsChanged);
} }
ClangDiagnosticConfigs ClangDiagnosticConfigsWidget::customConfigs() const ClangDiagnosticConfigs ClangDiagnosticConfigsWidget::customConfigs() const

View File

@@ -77,7 +77,7 @@ private:
void onClazyTreeChanged(); void onClazyTreeChanged();
void onClangTidyTreeItemClicked(const QModelIndex &index); void onClangTidyTreeItemClicked(const QModelIndex &index);
void onDiagnosticOptionsEdited(); void onClangOnlyOptionsChanged();
void syncWidgetsToModel(const Core::Id &configToSelect = Core::Id()); void syncWidgetsToModel(const Core::Id &configToSelect = Core::Id());
void syncConfigChooserToModel(const Core::Id &configToSelect = Core::Id()); void syncConfigChooserToModel(const Core::Id &configToSelect = Core::Id());
@@ -104,8 +104,8 @@ private:
void connectConfigChooserCurrentIndex(); void connectConfigChooserCurrentIndex();
void disconnectConfigChooserCurrentIndex(); void disconnectConfigChooserCurrentIndex();
void connectDiagnosticOptionsChanged(); void connectClangOnlyOptionsChanged();
void disconnectDiagnosticOptionsChanged(); void disconnectClangOnlyOptionsChanged();
private: private:
Ui::ClangDiagnosticConfigsWidget *m_ui; Ui::ClangDiagnosticConfigsWidget *m_ui;

View File

@@ -99,12 +99,14 @@ CompilerOptionsBuilder::CompilerOptionsBuilder(const ProjectPart &projectPart,
UseSystemHeader useSystemHeader, UseSystemHeader useSystemHeader,
UseTweakedHeaderPaths useTweakedHeaderPaths, UseTweakedHeaderPaths useTweakedHeaderPaths,
UseLanguageDefines useLanguageDefines, UseLanguageDefines useLanguageDefines,
UseBuildSystemWarnings useBuildSystemWarnings,
const QString &clangVersion, const QString &clangVersion,
const QString &clangResourceDirectory) const QString &clangResourceDirectory)
: m_projectPart(projectPart) : m_projectPart(projectPart)
, m_useSystemHeader(useSystemHeader) , m_useSystemHeader(useSystemHeader)
, m_useTweakedHeaderPaths(useTweakedHeaderPaths) , m_useTweakedHeaderPaths(useTweakedHeaderPaths)
, m_useLanguageDefines(useLanguageDefines) , m_useLanguageDefines(useLanguageDefines)
, m_useBuildSystemWarnings(useBuildSystemWarnings)
, m_clangVersion(clangVersion) , m_clangVersion(clangVersion)
, m_clangResourceDirectory(clangResourceDirectory) , m_clangResourceDirectory(clangResourceDirectory)
{ {
@@ -707,10 +709,11 @@ void CompilerOptionsBuilder::evaluateCompilerFlags()
continue; continue;
} }
// Ignore warning flags as these interfere with ouser user-configured diagnostics. // Ignore warning flags as these interfere with our user-configured diagnostics.
// Note that once "-w" is provided, no warnings will be emitted, even if "-Wall" follows. // Note that once "-w" is provided, no warnings will be emitted, even if "-Wall" follows.
if (option.startsWith("-w", Qt::CaseInsensitive) if (m_useBuildSystemWarnings == UseBuildSystemWarnings::No
|| option.startsWith("/w", Qt::CaseInsensitive) || option.startsWith("-pedantic")) { && (option.startsWith("-w", Qt::CaseInsensitive)
|| option.startsWith("/w", Qt::CaseInsensitive) || option.startsWith("-pedantic"))) {
// -w, -W, /w, /W... // -w, -W, /w, /W...
continue; continue;
} }

View File

@@ -36,6 +36,7 @@ enum class UseSystemHeader : char { Yes, No };
enum class UseTweakedHeaderPaths : char { Yes, No }; enum class UseTweakedHeaderPaths : char { Yes, No };
enum class UseToolchainMacros : char { Yes, No }; enum class UseToolchainMacros : char { Yes, No };
enum class UseLanguageDefines : char { Yes, No }; enum class UseLanguageDefines : char { Yes, No };
enum class UseBuildSystemWarnings : char { Yes, No };
CPPTOOLS_EXPORT QStringList XclangArgs(const QStringList &args); CPPTOOLS_EXPORT QStringList XclangArgs(const QStringList &args);
CPPTOOLS_EXPORT QStringList clangArgsForCl(const QStringList &args); CPPTOOLS_EXPORT QStringList clangArgsForCl(const QStringList &args);
@@ -43,12 +44,14 @@ CPPTOOLS_EXPORT QStringList clangArgsForCl(const QStringList &args);
class CPPTOOLS_EXPORT CompilerOptionsBuilder class CPPTOOLS_EXPORT CompilerOptionsBuilder
{ {
public: public:
CompilerOptionsBuilder(const ProjectPart &projectPart, CompilerOptionsBuilder(
UseSystemHeader useSystemHeader = UseSystemHeader::No, const ProjectPart &projectPart,
UseTweakedHeaderPaths useTweakedHeaderPaths = UseTweakedHeaderPaths::No, UseSystemHeader useSystemHeader = UseSystemHeader::No,
UseLanguageDefines useLanguageDefines = UseLanguageDefines::No, UseTweakedHeaderPaths useTweakedHeaderPaths = UseTweakedHeaderPaths::No,
const QString &clangVersion = QString(), UseLanguageDefines useLanguageDefines = UseLanguageDefines::No,
const QString &clangResourceDirectory = QString()); UseBuildSystemWarnings useBuildSystemWarnings = UseBuildSystemWarnings::No,
const QString &clangVersion = QString(),
const QString &clangResourceDirectory = QString());
QStringList build(ProjectFile::Kind fileKind, UsePrecompiledHeaders usePrecompiledHeaders); QStringList build(ProjectFile::Kind fileKind, UsePrecompiledHeaders usePrecompiledHeaders);
QStringList options() const { return m_options; } QStringList options() const { return m_options; }
@@ -99,6 +102,7 @@ private:
const UseSystemHeader m_useSystemHeader; const UseSystemHeader m_useSystemHeader;
const UseTweakedHeaderPaths m_useTweakedHeaderPaths; const UseTweakedHeaderPaths m_useTweakedHeaderPaths;
const UseLanguageDefines m_useLanguageDefines; const UseLanguageDefines m_useLanguageDefines;
const UseBuildSystemWarnings m_useBuildSystemWarnings;
const QString m_clangVersion; const QString m_clangVersion;
const QString m_clangResourceDirectory; const QString m_clangResourceDirectory;

View File

@@ -27,6 +27,7 @@
#include "clangdiagnosticconfigsmodel.h" #include "clangdiagnosticconfigsmodel.h"
#include "cpptoolsconstants.h" #include "cpptoolsconstants.h"
#include "cpptoolsreuse.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -79,6 +80,24 @@ static QString skipIndexingBigFilesKey()
static QString indexerFileSizeLimitKey() static QString indexerFileSizeLimitKey()
{ return QLatin1String(Constants::CPPTOOLS_INDEXER_FILE_SIZE_LIMIT); } { return QLatin1String(Constants::CPPTOOLS_INDEXER_FILE_SIZE_LIMIT); }
static QString convertToNewClazyChecksFormat(const QString &checks)
{
// Before Qt Creator 4.9 valid values for checks were: "", "levelN".
// Starting with Qt Creator 4.9, checks are a comma-separated string of checks: "x,y,z".
if (checks.isEmpty())
return checks;
if (checks.size() == 6 && checks.startsWith("level")) {
bool ok = false;
const int level = checks.mid(5).toInt(&ok);
QTC_ASSERT(ok, return QString());
return clazyChecksForLevel(level);
}
return checks;
}
static ClangDiagnosticConfigs customDiagnosticConfigsFromSettings(QSettings *s) static ClangDiagnosticConfigs customDiagnosticConfigsFromSettings(QSettings *s)
{ {
QTC_ASSERT(s->group() == QLatin1String(Constants::CPPTOOLS_SETTINGSGROUP), QTC_ASSERT(s->group() == QLatin1String(Constants::CPPTOOLS_SETTINGSGROUP),
@@ -98,7 +117,9 @@ static ClangDiagnosticConfigs customDiagnosticConfigsFromSettings(QSettings *s)
s->value(clangDiagnosticConfigsArrayClangTidyModeKey()).toInt())); s->value(clangDiagnosticConfigsArrayClangTidyModeKey()).toInt()));
config.setClangTidyChecks( config.setClangTidyChecks(
s->value(clangDiagnosticConfigsArrayClangTidyChecksKey()).toString()); s->value(clangDiagnosticConfigsArrayClangTidyChecksKey()).toString());
config.setClazyChecks(s->value(clangDiagnosticConfigsArrayClazyChecksKey()).toString());
const QString clazyChecks = s->value(clangDiagnosticConfigsArrayClazyChecksKey()).toString();
config.setClazyChecks(convertToNewClazyChecksFormat(clazyChecks));
configs.append(config); configs.append(config);
} }
s->endArray(); s->endArray();

View File

@@ -27,6 +27,7 @@
#include "cppcodemodelsettings.h" #include "cppcodemodelsettings.h"
#include "cpptoolsplugin.h" #include "cpptoolsplugin.h"
#include "cpptools_clazychecks.h"
#include <coreplugin/documentmanager.h> #include <coreplugin/documentmanager.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
@@ -287,4 +288,14 @@ UsePrecompiledHeaders getPchUsage()
return UsePrecompiledHeaders::Yes; return UsePrecompiledHeaders::Yes;
} }
QString clazyChecksForLevel(int level)
{
QStringList checks;
for (const Constants::ClazyCheckInfo &check : Constants::CLAZY_CHECKS) {
if (check.level == level)
checks << check.name;
}
return checks.join(',');
}
} // CppTools } // CppTools

View File

@@ -80,4 +80,6 @@ UsePrecompiledHeaders CPPTOOLS_EXPORT getPchUsage();
int indexerFileSizeLimitInMb(); int indexerFileSizeLimitInMb();
bool fileSizeExceedsLimit(const QFileInfo &fileInfo, int sizeLimitInMb); bool fileSizeExceedsLimit(const QFileInfo &fileInfo, int sizeLimitInMb);
QString clazyChecksForLevel(int level);
} // CppTools } // CppTools

View File

@@ -1561,7 +1561,7 @@ void DebuggerPluginPrivate::attachCore()
const QString lastExternalKit = configValue("LastExternalKit").toString(); const QString lastExternalKit = configValue("LastExternalKit").toString();
if (!lastExternalKit.isEmpty()) if (!lastExternalKit.isEmpty())
dlg.setKitId(Id::fromString(lastExternalKit)); dlg.setKitId(Id::fromString(lastExternalKit));
dlg.setLocalExecutableFile(configValue("LastExternalExecutableFile").toString()); dlg.setSymbolFile(configValue("LastExternalExecutableFile").toString());
dlg.setLocalCoreFile(configValue("LastLocalCoreFile").toString()); dlg.setLocalCoreFile(configValue("LastLocalCoreFile").toString());
dlg.setRemoteCoreFile(configValue("LastRemoteCoreFile").toString()); dlg.setRemoteCoreFile(configValue("LastRemoteCoreFile").toString());
dlg.setOverrideStartScript(configValue("LastExternalStartScript").toString()); dlg.setOverrideStartScript(configValue("LastExternalStartScript").toString());
@@ -1570,7 +1570,7 @@ void DebuggerPluginPrivate::attachCore()
if (dlg.exec() != QDialog::Accepted) if (dlg.exec() != QDialog::Accepted)
return; return;
setConfigValue("LastExternalExecutableFile", dlg.localExecutableFile()); setConfigValue("LastExternalExecutableFile", dlg.symbolFile());
setConfigValue("LastLocalCoreFile", dlg.localCoreFile()); setConfigValue("LastLocalCoreFile", dlg.localCoreFile());
setConfigValue("LastRemoteCoreFile", dlg.remoteCoreFile()); setConfigValue("LastRemoteCoreFile", dlg.remoteCoreFile());
setConfigValue("LastExternalKit", dlg.kit()->id().toSetting()); setConfigValue("LastExternalKit", dlg.kit()->id().toSetting());
@@ -1580,7 +1580,7 @@ void DebuggerPluginPrivate::attachCore()
IDevice::ConstPtr device = DeviceKitInformation::device(dlg.kit()); IDevice::ConstPtr device = DeviceKitInformation::device(dlg.kit());
auto runControl = new RunControl(device, ProjectExplorer::Constants::DEBUG_RUN_MODE); auto runControl = new RunControl(device, ProjectExplorer::Constants::DEBUG_RUN_MODE);
auto debugger = new DebuggerRunTool(runControl, dlg.kit()); auto debugger = new DebuggerRunTool(runControl, dlg.kit());
debugger->setInferiorExecutable(dlg.localExecutableFile()); debugger->setInferiorExecutable(dlg.symbolFile());
debugger->setCoreFileName(dlg.localCoreFile()); debugger->setCoreFileName(dlg.localCoreFile());
debugger->setRunControlName(tr("Core file \"%1\"") debugger->setRunControlName(tr("Core file \"%1\"")
.arg(dlg.useLocalCoreFile() ? dlg.localCoreFile() : dlg.remoteCoreFile())); .arg(dlg.useLocalCoreFile() ? dlg.localCoreFile() : dlg.remoteCoreFile()));

View File

@@ -207,7 +207,7 @@ public:
QCheckBox *forceLocalCheckBox; QCheckBox *forceLocalCheckBox;
QLabel *forceLocalLabel; QLabel *forceLocalLabel;
PathChooser *localExecFileName; PathChooser *symbolFileName;
PathChooser *localCoreFileName; PathChooser *localCoreFileName;
QLineEdit *remoteCoreFileName; QLineEdit *remoteCoreFileName;
QPushButton *selectRemoteCoreButton; QPushButton *selectRemoteCoreButton;
@@ -220,11 +220,11 @@ public:
{ {
bool isValid() const bool isValid() const
{ {
return validKit && validLocalExecFilename && validCoreFilename; return validKit && validSymbolFilename && validCoreFilename;
} }
bool validKit; bool validKit;
bool validLocalExecFilename; bool validSymbolFilename;
bool validCoreFilename; bool validCoreFilename;
bool localCoreFile; bool localCoreFile;
bool localKit; bool localKit;
@@ -235,7 +235,7 @@ public:
State st; State st;
st.localCoreFile = p.useLocalCoreFile(); st.localCoreFile = p.useLocalCoreFile();
st.validKit = (kitChooser->currentKit() != nullptr); st.validKit = (kitChooser->currentKit() != nullptr);
st.validLocalExecFilename = localExecFileName->isValid(); st.validSymbolFilename = symbolFileName->isValid();
if (st.localCoreFile) if (st.localCoreFile)
st.validCoreFilename = localCoreFileName->isValid(); st.validCoreFilename = localCoreFileName->isValid();
@@ -274,10 +274,14 @@ AttachCoreDialog::AttachCoreDialog(QWidget *parent)
d->localCoreFileName->setExpectedKind(PathChooser::File); d->localCoreFileName->setExpectedKind(PathChooser::File);
d->localCoreFileName->setPromptDialogTitle(tr("Select Core File")); d->localCoreFileName->setPromptDialogTitle(tr("Select Core File"));
d->localExecFileName = new PathChooser(this); d->symbolFileName = new PathChooser(this);
d->localExecFileName->setHistoryCompleter("LocalExecutable"); d->symbolFileName->setHistoryCompleter("LocalExecutable");
d->localExecFileName->setExpectedKind(PathChooser::File); d->symbolFileName->setExpectedKind(PathChooser::File);
d->localExecFileName->setPromptDialogTitle(tr("Select Executable")); d->symbolFileName->setPromptDialogTitle(tr("Select Executable or Symbol File"));
d->symbolFileName->setToolTip(
tr("Select a file containing debug information corresponding to the core file. "
"Typically, this is the executable or a *.debug file if the debug "
"information is stored separately from the executable."));
d->overrideStartScriptFileName = new PathChooser(this); d->overrideStartScriptFileName = new PathChooser(this);
d->overrideStartScriptFileName->setHistoryCompleter("Debugger.StartupScript.History"); d->overrideStartScriptFileName->setHistoryCompleter("Debugger.StartupScript.History");
@@ -296,7 +300,7 @@ AttachCoreDialog::AttachCoreDialog(QWidget *parent)
formLayout->addRow(tr("Kit:"), d->kitChooser); formLayout->addRow(tr("Kit:"), d->kitChooser);
formLayout->addRow(d->forceLocalLabel, d->forceLocalCheckBox); formLayout->addRow(d->forceLocalLabel, d->forceLocalCheckBox);
formLayout->addRow(tr("Core file:"), coreLayout); formLayout->addRow(tr("Core file:"), coreLayout);
formLayout->addRow(tr("&Executable:"), d->localExecFileName); formLayout->addRow(tr("&Executable or symbol file:"), d->symbolFileName);
formLayout->addRow(tr("Override &start script:"), d->overrideStartScriptFileName); formLayout->addRow(tr("Override &start script:"), d->overrideStartScriptFileName);
auto line = new QFrame(this); auto line = new QFrame(this);
@@ -321,7 +325,7 @@ int AttachCoreDialog::exec()
{ {
connect(d->selectRemoteCoreButton, &QAbstractButton::clicked, this, &AttachCoreDialog::selectRemoteCoreFile); connect(d->selectRemoteCoreButton, &QAbstractButton::clicked, this, &AttachCoreDialog::selectRemoteCoreFile);
connect(d->remoteCoreFileName, &QLineEdit::textChanged, this, &AttachCoreDialog::coreFileChanged); connect(d->remoteCoreFileName, &QLineEdit::textChanged, this, &AttachCoreDialog::coreFileChanged);
connect(d->localExecFileName, &PathChooser::rawPathChanged, this, &AttachCoreDialog::changed); connect(d->symbolFileName, &PathChooser::rawPathChanged, this, &AttachCoreDialog::changed);
connect(d->localCoreFileName, &PathChooser::rawPathChanged, this, &AttachCoreDialog::coreFileChanged); connect(d->localCoreFileName, &PathChooser::rawPathChanged, this, &AttachCoreDialog::coreFileChanged);
connect(d->forceLocalCheckBox, &QCheckBox::stateChanged, this, &AttachCoreDialog::changed); connect(d->forceLocalCheckBox, &QCheckBox::stateChanged, this, &AttachCoreDialog::changed);
connect(d->kitChooser, &KitChooser::currentIndexChanged, this, &AttachCoreDialog::changed); connect(d->kitChooser, &KitChooser::currentIndexChanged, this, &AttachCoreDialog::changed);
@@ -337,8 +341,8 @@ int AttachCoreDialog::exec()
d->localCoreFileName->setFocus(); d->localCoreFileName->setFocus();
else else
d->remoteCoreFileName->setFocus(); d->remoteCoreFileName->setFocus();
} else if (!st.validLocalExecFilename) { } else if (!st.validSymbolFilename) {
d->localExecFileName->setFocus(); d->symbolFileName->setFocus();
} }
return QDialog::exec(); return QDialog::exec();
@@ -366,9 +370,9 @@ void AttachCoreDialog::coreFileChanged(const QString &core)
Runnable debugger = DebuggerKitInformation::runnable(k); Runnable debugger = DebuggerKitInformation::runnable(k);
CoreInfo cinfo = CoreInfo::readExecutableNameFromCore(debugger, core); CoreInfo cinfo = CoreInfo::readExecutableNameFromCore(debugger, core);
if (!cinfo.foundExecutableName.isEmpty()) if (!cinfo.foundExecutableName.isEmpty())
d->localExecFileName->setFileName(FileName::fromString(cinfo.foundExecutableName)); d->symbolFileName->setFileName(FileName::fromString(cinfo.foundExecutableName));
else if (!d->localExecFileName->isValid() && !cinfo.rawStringFromCore.isEmpty()) else if (!d->symbolFileName->isValid() && !cinfo.rawStringFromCore.isEmpty())
d->localExecFileName->setFileName(FileName::fromString(cinfo.rawStringFromCore)); d->symbolFileName->setFileName(FileName::fromString(cinfo.rawStringFromCore));
} }
changed(); changed();
} }
@@ -411,14 +415,14 @@ QString AttachCoreDialog::localCoreFile() const
return d->localCoreFileName->path(); return d->localCoreFileName->path();
} }
QString AttachCoreDialog::localExecutableFile() const QString AttachCoreDialog::symbolFile() const
{ {
return d->localExecFileName->path(); return d->symbolFileName->path();
} }
void AttachCoreDialog::setLocalExecutableFile(const QString &fileName) void AttachCoreDialog::setSymbolFile(const QString &symbolFileName)
{ {
d->localExecFileName->setPath(fileName); d->symbolFileName->setPath(symbolFileName);
} }
void AttachCoreDialog::setLocalCoreFile(const QString &fileName) void AttachCoreDialog::setLocalCoreFile(const QString &fileName)

View File

@@ -45,7 +45,7 @@ public:
int exec() override; int exec() override;
QString localExecutableFile() const; QString symbolFile() const;
QString localCoreFile() const; QString localCoreFile() const;
QString remoteCoreFile() const; QString remoteCoreFile() const;
QString overrideStartScript() const; QString overrideStartScript() const;
@@ -55,7 +55,7 @@ public:
// For persistance. // For persistance.
ProjectExplorer::Kit *kit() const; ProjectExplorer::Kit *kit() const;
void setLocalExecutableFile(const QString &executable); void setSymbolFile(const QString &symbolFileName);
void setLocalCoreFile(const QString &core); void setLocalCoreFile(const QString &core);
void setRemoteCoreFile(const QString &core); void setRemoteCoreFile(const QString &core);
void setOverrideStartScript(const QString &scriptName); void setOverrideStartScript(const QString &scriptName);

View File

@@ -39,11 +39,13 @@
#include <texteditor/semantichighlighter.h> #include <texteditor/semantichighlighter.h>
#include <texteditor/textdocument.h> #include <texteditor/textdocument.h>
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
#include <texteditor/textmark.h>
#include <projectexplorer/project.h> #include <projectexplorer/project.h>
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <utils/mimetypes/mimedatabase.h> #include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcprocess.h> #include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h> #include <utils/synchronousprocess.h>
#include <utils/utilsicons.h>
#include <QDebug> #include <QDebug>
#include <QLoggingCategory> #include <QLoggingCategory>
@@ -62,6 +64,25 @@ namespace LanguageClient {
static Q_LOGGING_CATEGORY(LOGLSPCLIENT, "qtc.languageclient.client", QtWarningMsg); static Q_LOGGING_CATEGORY(LOGLSPCLIENT, "qtc.languageclient.client", QtWarningMsg);
class TextMark : public TextEditor::TextMark
{
public:
TextMark(const Utils::FileName &fileName, const Diagnostic &diag)
: TextEditor::TextMark(fileName, diag.range().start().line() + 1, "lspmark")
{
using namespace Utils;
setLineAnnotation(diag.message());
setToolTip(diag.message());
const bool isError
= diag.severity().value_or(DiagnosticSeverity::Hint) == DiagnosticSeverity::Error;
setColor(isError ? Theme::CodeModel_Error_TextMarkColor
: Theme::CodeModel_Warning_TextMarkColor);
setIcon(isError ? Icons::CODEMODEL_ERROR.icon()
: Icons::CODEMODEL_WARNING.icon());
}
};
Client::Client(BaseClientInterface *clientInterface) Client::Client(BaseClientInterface *clientInterface)
: m_id(Core::Id::fromString(QUuid::createUuid().toString())) : m_id(Core::Id::fromString(QUuid::createUuid().toString()))
, m_completionProvider(this) , m_completionProvider(this)
@@ -88,6 +109,8 @@ Client::~Client()
widget->setRefactorMarkers(RefactorMarker::filterOutType(widget->refactorMarkers(), id())); widget->setRefactorMarkers(RefactorMarker::filterOutType(widget->refactorMarkers(), id()));
} }
} }
for (const DocumentUri &uri : m_diagnostics.keys())
removeDiagnostics(uri);
} }
void Client::initialize() void Client::initialize()
@@ -155,10 +178,12 @@ void Client::openDocument(Core::IDocument *document)
return; return;
} }
} }
auto uri = DocumentUri::fromFileName(filePath);
showDiagnostics(uri);
auto textDocument = qobject_cast<TextDocument *>(document); auto textDocument = qobject_cast<TextDocument *>(document);
TextDocumentItem item; TextDocumentItem item;
item.setLanguageId(TextDocumentItem::mimeTypeToLanguageId(document->mimeType())); item.setLanguageId(TextDocumentItem::mimeTypeToLanguageId(document->mimeType()));
item.setUri(DocumentUri::fromFileName(filePath)); item.setUri(uri);
item.setText(QString::fromUtf8(document->contents())); item.setText(QString::fromUtf8(document->contents()));
item.setVersion(textDocument ? textDocument->document()->revision() : 0); item.setVersion(textDocument ? textDocument->document()->revision() : 0);
@@ -673,6 +698,8 @@ bool Client::reset()
m_openedDocument.clear(); m_openedDocument.clear();
m_serverCapabilities = ServerCapabilities(); m_serverCapabilities = ServerCapabilities();
m_dynamicCapabilities.reset(); m_dynamicCapabilities.reset();
for (const DocumentUri &uri : m_diagnostics.keys())
removeDiagnostics(uri);
return true; return true;
} }
@@ -749,6 +776,25 @@ void Client::showMessageBox(const ShowMessageRequestParams &message, const Messa
box->show(); box->show();
} }
void Client::showDiagnostics(const DocumentUri &uri)
{
if (TextEditor::TextDocument *doc = textDocumentForFileName(uri.toFileName())) {
for (TextMark *mark : m_diagnostics.value(uri))
doc->addMark(mark);
}
}
void Client::removeDiagnostics(const DocumentUri &uri)
{
TextEditor::TextDocument *doc = textDocumentForFileName(uri.toFileName());
for (TextMark *mark : m_diagnostics.take(uri)) {
if (doc)
doc->removeMark(mark);
delete mark;
}
}
void Client::handleResponse(const MessageId &id, const QByteArray &content, QTextCodec *codec) void Client::handleResponse(const MessageId &id, const QByteArray &content, QTextCodec *codec)
{ {
if (auto handler = m_responseHandlers[id]) if (auto handler = m_responseHandlers[id])
@@ -763,7 +809,7 @@ void Client::handleMethod(const QString &method, MessageId id, const IContent *c
auto params = dynamic_cast<const PublishDiagnosticsNotification *>(content)->params().value_or(PublishDiagnosticsParams()); auto params = dynamic_cast<const PublishDiagnosticsNotification *>(content)->params().value_or(PublishDiagnosticsParams());
paramsValid = params.isValid(&error); paramsValid = params.isValid(&error);
if (paramsValid) if (paramsValid)
LanguageClientManager::publishDiagnostics(m_id, params, this); handleDiagnostics(params);
} else if (method == LogMessageNotification::methodName) { } else if (method == LogMessageNotification::methodName) {
auto params = dynamic_cast<const LogMessageNotification *>(content)->params().value_or(LogMessageParams()); auto params = dynamic_cast<const LogMessageNotification *>(content)->params().value_or(LogMessageParams());
paramsValid = params.isValid(&error); paramsValid = params.isValid(&error);
@@ -823,6 +869,21 @@ void Client::handleMethod(const QString &method, MessageId id, const IContent *c
delete content; delete content;
} }
void Client::handleDiagnostics(const PublishDiagnosticsParams &params)
{
const DocumentUri &uri = params.uri();
removeDiagnostics(uri);
const QList<Diagnostic> &diagnostics = params.diagnostics();
m_diagnostics[uri] =
Utils::transform(diagnostics, [fileName = uri.toFileName()](const Diagnostic &diagnostic) {
return new TextMark(fileName, diagnostic);
});
showDiagnostics(uri);
requestCodeActions(uri, diagnostics);
}
void Client::intializeCallback(const InitializeRequest::Response &initResponse) void Client::intializeCallback(const InitializeRequest::Response &initResponse)
{ {
QTC_ASSERT(m_state == InitializeRequested, return); QTC_ASSERT(m_state == InitializeRequested, return);

View File

@@ -33,12 +33,13 @@
#include <coreplugin/messagemanager.h> #include <coreplugin/messagemanager.h>
#include <utils/link.h> #include <utils/link.h>
#include <languageserverprotocol/client.h>
#include <languageserverprotocol/diagnostics.h>
#include <languageserverprotocol/initializemessages.h> #include <languageserverprotocol/initializemessages.h>
#include <languageserverprotocol/languagefeatures.h>
#include <languageserverprotocol/messages.h>
#include <languageserverprotocol/shutdownmessages.h> #include <languageserverprotocol/shutdownmessages.h>
#include <languageserverprotocol/textsynchronization.h> #include <languageserverprotocol/textsynchronization.h>
#include <languageserverprotocol/messages.h>
#include <languageserverprotocol/client.h>
#include <languageserverprotocol/languagefeatures.h>
#include <QBuffer> #include <QBuffer>
#include <QHash> #include <QHash>
@@ -50,13 +51,15 @@ namespace Core { class IDocument; }
namespace ProjectExplorer { class Project; } namespace ProjectExplorer { class Project; }
namespace TextEditor namespace TextEditor
{ {
class TextDocument; class TextDocument;
class TextEditorWidget; class TextEditorWidget;
class TextMark;
} }
namespace LanguageClient { namespace LanguageClient {
class BaseClientInterface; class BaseClientInterface;
class TextMark;
class Client : public QObject class Client : public QObject
{ {
@@ -153,6 +156,8 @@ private:
void handleMethod(const QString &method, LanguageServerProtocol::MessageId id, void handleMethod(const QString &method, LanguageServerProtocol::MessageId id,
const LanguageServerProtocol::IContent *content); const LanguageServerProtocol::IContent *content);
void handleDiagnostics(const LanguageServerProtocol::PublishDiagnosticsParams &params);
void intializeCallback(const LanguageServerProtocol::InitializeRequest::Response &initResponse); void intializeCallback(const LanguageServerProtocol::InitializeRequest::Response &initResponse);
void shutDownCallback(const LanguageServerProtocol::ShutdownRequest::Response &shutdownResponse); void shutDownCallback(const LanguageServerProtocol::ShutdownRequest::Response &shutdownResponse);
bool sendWorkspceFolderChanges() const; bool sendWorkspceFolderChanges() const;
@@ -162,6 +167,9 @@ private:
void showMessageBox(const LanguageServerProtocol::ShowMessageRequestParams &message, void showMessageBox(const LanguageServerProtocol::ShowMessageRequestParams &message,
const LanguageServerProtocol::MessageId &id); const LanguageServerProtocol::MessageId &id);
void showDiagnostics(const LanguageServerProtocol::DocumentUri &uri);
void removeDiagnostics(const LanguageServerProtocol::DocumentUri &uri);
using ContentHandler = std::function<void(const QByteArray &, QTextCodec *, QString &, using ContentHandler = std::function<void(const QByteArray &, QTextCodec *, QString &,
LanguageServerProtocol::ResponseHandlers, LanguageServerProtocol::ResponseHandlers,
LanguageServerProtocol::MethodHandler)>; LanguageServerProtocol::MethodHandler)>;
@@ -180,6 +188,7 @@ private:
QHash<LanguageServerProtocol::DocumentUri, LanguageServerProtocol::MessageId> m_highlightRequests; QHash<LanguageServerProtocol::DocumentUri, LanguageServerProtocol::MessageId> m_highlightRequests;
int m_restartsLeft = 5; int m_restartsLeft = 5;
QScopedPointer<BaseClientInterface> m_clientInterface; QScopedPointer<BaseClientInterface> m_clientInterface;
QMap<LanguageServerProtocol::DocumentUri, QList<TextMark *>> m_diagnostics;
}; };
} // namespace LanguageClient } // namespace LanguageClient

View File

@@ -49,30 +49,6 @@ namespace LanguageClient {
static LanguageClientManager *managerInstance = nullptr; static LanguageClientManager *managerInstance = nullptr;
class LanguageClientMark : public TextEditor::TextMark
{
public:
LanguageClientMark(const Utils::FileName &fileName, const Diagnostic &diag)
: TextEditor::TextMark(fileName, diag.range().start().line() + 1, "lspmark")
{
using namespace Utils;
setLineAnnotation(diag.message());
setToolTip(diag.message());
const bool isError
= diag.severity().value_or(DiagnosticSeverity::Hint) == DiagnosticSeverity::Error;
setColor(isError ? Theme::CodeModel_Error_TextMarkColor
: Theme::CodeModel_Warning_TextMarkColor);
setIcon(isError ? Icons::CODEMODEL_ERROR.icon()
: Icons::CODEMODEL_WARNING.icon());
}
void removedFromEditor() override
{
LanguageClientManager::removeMark(this);
}
};
LanguageClientManager::LanguageClientManager() LanguageClientManager::LanguageClientManager()
{ {
JsonRpcMessageHandler::registerMessageProvider<PublishDiagnosticsNotification>(); JsonRpcMessageHandler::registerMessageProvider<PublishDiagnosticsNotification>();
@@ -107,68 +83,6 @@ void LanguageClientManager::init()
managerInstance, &LanguageClientManager::projectRemoved); managerInstance, &LanguageClientManager::projectRemoved);
} }
void LanguageClientManager::publishDiagnostics(const Core::Id &id,
const PublishDiagnosticsParams &params,
Client *publishingClient)
{
const Utils::FileName fileName = params.uri().toFileName();
TextEditor::TextDocument *doc = textDocumentForFileName(fileName);
if (!doc)
return;
removeMarks(fileName, id);
managerInstance->m_marks[fileName][id].reserve(params.diagnostics().size());
QList<Diagnostic> diagnostics = params.diagnostics();
for (const Diagnostic& diagnostic : diagnostics) {
auto mark = new LanguageClientMark(fileName, diagnostic);
managerInstance->m_marks[fileName][id].append(mark);
doc->addMark(mark);
}
publishingClient->requestCodeActions(params.uri(), diagnostics);
}
void LanguageClientManager::removeMark(LanguageClientMark *mark)
{
for (auto &marks : managerInstance->m_marks[mark->fileName()])
marks.removeAll(mark);
delete mark;
}
void LanguageClientManager::removeMarks(const Utils::FileName &fileName)
{
TextEditor::TextDocument *doc = textDocumentForFileName(fileName);
if (!doc)
return;
for (const auto &marks : qAsConst(managerInstance->m_marks[fileName])) {
for (TextEditor::TextMark *mark : marks) {
doc->removeMark(mark);
delete mark;
}
}
managerInstance->m_marks[fileName].clear();
}
void LanguageClientManager::removeMarks(const Utils::FileName &fileName, const Core::Id &id)
{
TextEditor::TextDocument *doc = textDocumentForFileName(fileName);
if (!doc)
return;
for (TextEditor::TextMark *mark : managerInstance->m_marks[fileName][id]) {
doc->removeMark(mark);
delete mark;
}
managerInstance->m_marks[fileName][id].clear();
}
void LanguageClientManager::removeMarks(const Core::Id &id)
{
for (const Utils::FileName &fileName : managerInstance->m_marks.keys())
removeMarks(fileName, id);
}
void LanguageClientManager::startClient(Client *client) void LanguageClientManager::startClient(Client *client)
{ {
QTC_ASSERT(client, return); QTC_ASSERT(client, return);
@@ -210,7 +124,6 @@ void LanguageClientManager::deleteClient(Client *client)
{ {
QTC_ASSERT(client, return); QTC_ASSERT(client, return);
client->disconnect(); client->disconnect();
managerInstance->removeMarks(client->id());
managerInstance->m_clients.removeAll(client); managerInstance->m_clients.removeAll(client);
client->deleteLater(); client->deleteLater();
} }
@@ -269,7 +182,6 @@ void LanguageClientManager::clientFinished(Client *client)
const bool unexpectedFinish = client->state() != Client::Shutdown const bool unexpectedFinish = client->state() != Client::Shutdown
&& client->state() != Client::ShutdownRequested; && client->state() != Client::ShutdownRequested;
if (unexpectedFinish && !m_shuttingDown && client->reset()) { if (unexpectedFinish && !m_shuttingDown && client->reset()) {
removeMarks(client->id());
client->disconnect(this); client->disconnect(this);
client->log(tr("Unexpectedly finished. Restarting in %1 seconds.").arg(restartTimeoutS), client->log(tr("Unexpectedly finished. Restarting in %1 seconds.").arg(restartTimeoutS),
Core::MessageManager::Flash); Core::MessageManager::Flash);
@@ -312,7 +224,6 @@ void LanguageClientManager::editorsClosed(const QList<Core::IEditor *> &editors)
{ {
for (auto iEditor : editors) { for (auto iEditor : editors) {
if (auto editor = qobject_cast<TextEditor::BaseTextEditor *>(iEditor)) { if (auto editor = qobject_cast<TextEditor::BaseTextEditor *>(iEditor)) {
removeMarks(editor->document()->filePath());
const DidCloseTextDocumentParams params(TextDocumentIdentifier( const DidCloseTextDocumentParams params(TextDocumentIdentifier(
DocumentUri::fromFileName(editor->document()->filePath()))); DocumentUri::fromFileName(editor->document()->filePath())));
for (Client *interface : reachableClients()) for (Client *interface : reachableClients())

View File

@@ -55,14 +55,6 @@ public:
static void init(); static void init();
static void publishDiagnostics(const Core::Id &id,
const LanguageServerProtocol::PublishDiagnosticsParams &params, Client *publishingClient);
static void removeMark(LanguageClientMark *mark);
static void removeMarks(const Utils::FileName &fileName);
static void removeMarks(const Utils::FileName &fileName, const Core::Id &id);
static void removeMarks(const Core::Id &id);
static void startClient(Client *client); static void startClient(Client *client);
static QVector<Client *> clients(); static QVector<Client *> clients();
@@ -101,7 +93,6 @@ private:
bool m_shuttingDown = false; bool m_shuttingDown = false;
QVector<Client *> m_clients; QVector<Client *> m_clients;
QHash<Utils::FileName, QHash<Core::Id, QVector<LanguageClientMark *>>> m_marks;
QHash<LanguageServerProtocol::MessageId, QList<Client *>> m_exclusiveRequests; QHash<LanguageServerProtocol::MessageId, QList<Client *>> m_exclusiveRequests;
friend class LanguageClientPlugin; friend class LanguageClientPlugin;

View File

@@ -36,10 +36,14 @@
#include <coreplugin/iversioncontrol.h> #include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h> #include <coreplugin/vcsmanager.h>
#include <cpptools/cpptoolsconstants.h> #include <cpptools/cpptoolsconstants.h>
#include <projectexplorer/editorconfiguration.h>
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <qtsupport/profilereader.h> #include <qtsupport/profilereader.h>
#include <texteditor/icodestylepreferences.h>
#include <texteditor/tabsettings.h>
#include <texteditor/texteditorsettings.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/filesystemwatcher.h> #include <utils/filesystemwatcher.h>
@@ -378,6 +382,19 @@ void QmakePriFile::watchFolders(const QSet<FileName> &folders)
m_watchedFolders = folderStrings; m_watchedFolders = folderStrings;
} }
QString QmakePriFile::continuationIndent() const
{
const EditorConfiguration *editorConf = project()->editorConfiguration();
const TextEditor::TabSettings &tabSettings = editorConf->useGlobalSettings()
? TextEditor::TextEditorSettings::codeStyle()->tabSettings()
: editorConf->codeStyle()->tabSettings();
if (tabSettings.m_continuationAlignBehavior == TextEditor::TabSettings::ContinuationAlignWithIndent
&& tabSettings.m_tabPolicy == TextEditor::TabSettings::TabsOnlyTabPolicy) {
return QString("\t");
}
return QString(tabSettings.m_indentSize, ' ');
}
bool QmakePriFile::knowsFile(const FileName &filePath) const bool QmakePriFile::knowsFile(const FileName &filePath) const
{ {
return m_recursiveEnumerateFiles.contains(filePath); return m_recursiveEnumerateFiles.contains(filePath);
@@ -747,7 +764,8 @@ bool QmakePriFile::renameFile(const QString &oldName,
ProWriter::addFiles(includeFile, &lines, ProWriter::addFiles(includeFile, &lines,
QStringList(newName), QStringList(newName),
varNameForAdding(mimeType)); varNameForAdding(mimeType),
continuationIndent());
if (mode == Change::Save) if (mode == Change::Save)
save(lines); save(lines);
includeFile->deref(); includeFile->deref();
@@ -777,7 +795,8 @@ void QmakePriFile::changeFiles(const QString &mimeType,
if (change == AddToProFile) { if (change == AddToProFile) {
// Use the first variable for adding. // Use the first variable for adding.
ProWriter::addFiles(includeFile, &lines, filePaths, varNameForAdding(mimeType)); ProWriter::addFiles(includeFile, &lines, filePaths, varNameForAdding(mimeType),
continuationIndent());
notChanged->clear(); notChanged->clear();
} else { // RemoveFromProFile } else { // RemoveFromProFile
QDir priFileDir = QDir(m_qmakeProFile->directoryPath().toString()); QDir priFileDir = QDir(m_qmakeProFile->directoryPath().toString());
@@ -818,7 +837,7 @@ bool QmakePriFile::setProVariable(const QString &var, const QStringList &values,
ProWriter::putVarValues(includeFile, &lines, values, var, ProWriter::putVarValues(includeFile, &lines, values, var,
ProWriter::PutFlags(flags), ProWriter::PutFlags(flags),
scope); scope, continuationIndent());
save(lines); save(lines);
includeFile->deref(); includeFile->deref();

View File

@@ -216,6 +216,8 @@ private:
static void processValues(Internal::QmakePriFileEvalResult &result); static void processValues(Internal::QmakePriFileEvalResult &result);
void watchFolders(const QSet<Utils::FileName> &folders); void watchFolders(const QSet<Utils::FileName> &folders);
QString continuationIndent() const;
QmakeProject *m_project = nullptr; QmakeProject *m_project = nullptr;
QmakeProFile *m_qmakeProFile = nullptr; QmakeProFile *m_qmakeProFile = nullptr;
QmakePriFile *m_parent = nullptr; QmakePriFile *m_parent = nullptr;

View File

@@ -25,6 +25,7 @@
#include "pathitem.h" #include "pathitem.h"
#include <exception.h>
#include <nodeproperty.h> #include <nodeproperty.h>
#include <variantproperty.h> #include <variantproperty.h>
#include <nodelistproperty.h> #include <nodelistproperty.h>
@@ -840,13 +841,17 @@ void PathItem::updatePathModelNodes(const QList<SelectionPoint> &changedPoints)
{ {
PathUpdateDisabler pathUpdateDisabler(this, PathUpdateDisabler::DontUpdatePath); PathUpdateDisabler pathUpdateDisabler(this, PathUpdateDisabler::DontUpdatePath);
RewriterTransaction rewriterTransaction = try {
formEditorItem()->qmlItemNode().view()->beginRewriterTransaction(QByteArrayLiteral("PathItem::createCubicSegmentContextMenu")); RewriterTransaction rewriterTransaction =
formEditorItem()->qmlItemNode().view()->beginRewriterTransaction(QByteArrayLiteral("PathItem::createCubicSegmentContextMenu"));
foreach (SelectionPoint changedPoint, changedPoints) foreach (SelectionPoint changedPoint, changedPoints)
changedPoint.controlPoint.updateModelNode(); changedPoint.controlPoint.updateModelNode();
rewriterTransaction.commit(); rewriterTransaction.commit();
} catch (const Exception &e) {
e.showException();
}
} }
void PathItem::disablePathUpdates() void PathItem::disablePathUpdates()

View File

@@ -43,6 +43,7 @@
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QKeyEvent>
#include <QToolBar> #include <QToolBar>
namespace QmlDesigner { namespace QmlDesigner {

View File

@@ -27,7 +27,11 @@ Project {
Depends { name: "QtSupport" } Depends { name: "QtSupport" }
Depends { name: "app_version_header" } Depends { name: "app_version_header" }
cpp.defines: base.concat("DESIGNER_CORE_LIBRARY") cpp.defines: base.concat([
"DESIGNER_CORE_LIBRARY",
"TIMELINE_QML_PATH=\"" + FileInfo.joinPaths(path, "qmldesignerextension",
"timelineeditor", "qml") + "\""
])
cpp.enableExceptions: true cpp.enableExceptions: true
cpp.includePaths: base.concat([ cpp.includePaths: base.concat([
".", ".",
@@ -51,6 +55,7 @@ Project {
"components/texteditor", "components/texteditor",
"qmldesignerextension", "qmldesignerextension",
"qmldesignerextension/connectioneditor", "qmldesignerextension/connectioneditor",
"qmldesignerextension/timelineeditor",
]) ])
Properties { Properties {
@@ -635,6 +640,72 @@ Project {
"texttool/textedititemwidget.h", "texttool/textedititemwidget.h",
"texttool/texttool.cpp", "texttool/texttool.cpp",
"texttool/texttool.h", "texttool/texttool.h",
"timelineeditor/canvas.cpp",
"timelineeditor/canvas.h",
"timelineeditor/canvasstyledialog.cpp",
"timelineeditor/canvasstyledialog.h",
"timelineeditor/easingcurve.cpp",
"timelineeditor/easingcurve.h",
"timelineeditor/easingcurvedialog.cpp",
"timelineeditor/easingcurvedialog.h",
"timelineeditor/preseteditor.cpp",
"timelineeditor/preseteditor.h",
"timelineeditor/setframevaluedialog.cpp",
"timelineeditor/setframevaluedialog.h",
"timelineeditor/setframevaluedialog.ui",
"timelineeditor/splineeditor.cpp",
"timelineeditor/splineeditor.h",
"timelineeditor/timeline.qrc",
"timelineeditor/timelineabstracttool.cpp",
"timelineeditor/timelineabstracttool.h",
"timelineeditor/timelineactions.cpp",
"timelineeditor/timelineactions.h",
"timelineeditor/timelineanimationform.cpp",
"timelineeditor/timelineanimationform.h",
"timelineeditor/timelineanimationform.ui",
"timelineeditor/timelineconstants.h",
"timelineeditor/timelinecontext.cpp",
"timelineeditor/timelinecontext.h",
"timelineeditor/timelinecontrols.cpp",
"timelineeditor/timelinecontrols.h",
"timelineeditor/timelineform.cpp",
"timelineeditor/timelineform.h",
"timelineeditor/timelineform.ui",
"timelineeditor/timelinegraphicslayout.cpp",
"timelineeditor/timelinegraphicslayout.h",
"timelineeditor/timelinegraphicsscene.cpp",
"timelineeditor/timelinegraphicsscene.h",
"timelineeditor/timelineicons.h",
"timelineeditor/timelineitem.cpp",
"timelineeditor/timelineitem.h",
"timelineeditor/timelinemovableabstractitem.cpp",
"timelineeditor/timelinemovableabstractitem.h",
"timelineeditor/timelinemovetool.cpp",
"timelineeditor/timelinemovetool.h",
"timelineeditor/timelineplaceholder.cpp",
"timelineeditor/timelineplaceholder.h",
"timelineeditor/timelinepropertyitem.cpp",
"timelineeditor/timelinepropertyitem.h",
"timelineeditor/timelinesectionitem.cpp",
"timelineeditor/timelinesectionitem.h",
"timelineeditor/timelineselectiontool.cpp",
"timelineeditor/timelineselectiontool.h",
"timelineeditor/timelinesettingsdialog.cpp",
"timelineeditor/timelinesettingsdialog.h",
"timelineeditor/timelinesettingsdialog.ui",
"timelineeditor/timelinesettingsmodel.cpp",
"timelineeditor/timelinesettingsmodel.h",
"timelineeditor/timelinetoolbar.cpp",
"timelineeditor/timelinetoolbar.h",
"timelineeditor/timelinetoolbutton.cpp",
"timelineeditor/timelinetoolbutton.h",
"timelineeditor/timelinetooldelegate.cpp",
"timelineeditor/timelineutils.cpp",
"timelineeditor/timelineutils.h",
"timelineeditor/timelineview.cpp",
"timelineeditor/timelineview.h",
"timelineeditor/timelinewidget.cpp",
"timelineeditor/timelinewidget.h",
] ]
} }

View File

@@ -563,6 +563,9 @@ public:
void processTooltipRequest(const QTextCursor &c); void processTooltipRequest(const QTextCursor &c);
bool processAnnotaionTooltipRequest(const QTextBlock &block, const QPoint &pos) const; bool processAnnotaionTooltipRequest(const QTextBlock &block, const QPoint &pos) const;
void showTextMarksToolTip(const QPoint &pos,
const TextMarks &marks,
const TextMark *mainTextMark = nullptr) const;
void transformSelection(TransformationMethod method); void transformSelection(TransformationMethod method);
void transformBlockSelection(TransformationMethod method); void transformBlockSelection(TransformationMethod method);
@@ -836,6 +839,68 @@ TextEditorWidgetPrivate::~TextEditorWidgetPrivate()
delete m_highlightScrollBarController; delete m_highlightScrollBarController;
} }
static QFrame *createSeparator(const QString &styleSheet)
{
QFrame* separator = new QFrame();
separator->setStyleSheet(styleSheet);
separator->setFrameShape(QFrame::HLine);
QSizePolicy sizePolicy = separator->sizePolicy();
sizePolicy.setHorizontalPolicy(QSizePolicy::MinimumExpanding);
separator->setSizePolicy(sizePolicy);
return separator;
}
static QLayout *createSeparatorLayout()
{
QString styleSheet = "color: gray";
QFrame* separator1 = createSeparator(styleSheet);
QFrame* separator2 = createSeparator(styleSheet);
auto label = new QLabel(TextEditorWidget::tr("Other annotations"));
label->setStyleSheet(styleSheet);
auto layout = new QHBoxLayout;
layout->addWidget(separator1);
layout->addWidget(label);
layout->addWidget(separator2);
return layout;
}
void TextEditorWidgetPrivate::showTextMarksToolTip(const QPoint &pos,
const TextMarks &marks,
const TextMark *mainTextMark) const
{
if (!mainTextMark && marks.isEmpty())
return; // Nothing to show
TextMarks allMarks = marks;
auto layout = new QGridLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(2);
if (mainTextMark) {
mainTextMark->addToToolTipLayout(layout);
if (allMarks.size() > 1)
layout->addLayout(createSeparatorLayout(), layout->rowCount(), 0, 1, -1);
}
Utils::sort(allMarks, [](const TextMark *mark1, const TextMark *mark2) {
return mark1->priority() > mark2->priority();
});
for (const TextMark *mark : qAsConst(allMarks)) {
if (mark != mainTextMark)
mark->addToToolTipLayout(layout);
}
layout->addWidget(DisplaySettings::createAnnotationSettingsLink(),
layout->rowCount(), 0, 1, -1, Qt::AlignRight);
ToolTip::show(pos, layout, q);
}
} // namespace Internal } // namespace Internal
/*! /*!
@@ -3490,6 +3555,13 @@ QPoint TextEditorWidget::toolTipPosition(const QTextCursor &c) const
return cursorPos + QPoint(d->m_extraArea->width(), HostOsInfo::isWindowsHost() ? -24 : -16); return cursorPos + QPoint(d->m_extraArea->width(), HostOsInfo::isWindowsHost() ? -24 : -16);
} }
void TextEditorWidget::showTextMarksToolTip(const QPoint &pos,
const TextMarks &marks,
const TextMark *mainTextMark) const
{
d->showTextMarksToolTip(pos, marks, mainTextMark);
}
void TextEditorWidgetPrivate::processTooltipRequest(const QTextCursor &c) void TextEditorWidgetPrivate::processTooltipRequest(const QTextCursor &c)
{ {
const QPoint toolTipPoint = q->toolTipPosition(c); const QPoint toolTipPoint = q->toolTipPosition(c);
@@ -3516,33 +3588,7 @@ bool TextEditorWidgetPrivate::processAnnotaionTooltipRequest(const QTextBlock &b
for (const AnnotationRect &annotationRect : m_annotationRects[block.blockNumber()]) { for (const AnnotationRect &annotationRect : m_annotationRects[block.blockNumber()]) {
if (!annotationRect.rect.contains(pos)) if (!annotationRect.rect.contains(pos))
continue; continue;
showTextMarksToolTip(q->mapToGlobal(pos), blockUserData->marks(), annotationRect.mark);
auto layout = new QGridLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(2);
annotationRect.mark->addToToolTipLayout(layout);
TextMarks marks = blockUserData->marks();
if (marks.size() > 1) {
QFrame* separator = new QFrame();
separator->setFrameShape(QFrame::HLine);
layout->addWidget(separator, layout->rowCount(), 0, 1, -1);
layout->addWidget(new QLabel(TextEditorWidget::tr("Other annotations:")),
layout->rowCount(),
0,
1,
-1);
Utils::sort(marks, [](const TextMark* mark1, const TextMark* mark2){
return mark1->priority() > mark2->priority();
});
for (const TextMark *mark : qAsConst(marks)) {
if (mark != annotationRect.mark)
mark->addToToolTipLayout(layout);
}
}
layout->addWidget(DisplaySettings::createAnnotationSettingsLink(),
layout->rowCount(), 0, 1, -1, Qt::AlignRight);
ToolTip::show(q->mapToGlobal(pos), layout, q);
return true; return true;
} }
return false; return false;
@@ -5787,16 +5833,10 @@ void TextEditorWidget::extraAreaMouseEvent(QMouseEvent *e)
int line = cursor.blockNumber() + 1; int line = cursor.blockNumber() + 1;
if (d->extraAreaPreviousMarkTooltipRequestedLine != line) { if (d->extraAreaPreviousMarkTooltipRequestedLine != line) {
if (auto data = static_cast<TextBlockUserData *>(cursor.block().userData())) { if (auto data = static_cast<TextBlockUserData *>(cursor.block().userData())) {
if (data->marks().isEmpty()) { if (data->marks().isEmpty())
ToolTip::hide(); ToolTip::hide();
} else { else
auto layout = new QGridLayout; d->showTextMarksToolTip(mapToGlobal(e->pos()), data->marks());
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(2);
foreach (TextMark *mark, data->marks())
mark->addToToolTipLayout(layout);
ToolTip::show(mapToGlobal(e->pos()), layout, this);
}
} }
} }
d->extraAreaPreviousMarkTooltipRequestedLine = line; d->extraAreaPreviousMarkTooltipRequestedLine = line;

View File

@@ -59,6 +59,7 @@ class HighlightScrollBarController;
namespace TextEditor { namespace TextEditor {
class TextDocument; class TextDocument;
class TextMark;
class BaseHoverHandler; class BaseHoverHandler;
class RefactorOverlay; class RefactorOverlay;
struct RefactorMarker; struct RefactorMarker;
@@ -68,6 +69,7 @@ class IAssistProvider;
class ICodeStylePreferences; class ICodeStylePreferences;
class CompletionAssistProvider; class CompletionAssistProvider;
using RefactorMarkers = QList<RefactorMarker>; using RefactorMarkers = QList<RefactorMarker>;
using TextMarks = QList<TextMark *>;
namespace Internal { namespace Internal {
class BaseTextEditorPrivate; class BaseTextEditorPrivate;
@@ -274,6 +276,9 @@ public:
QRegion translatedLineRegion(int lineStart, int lineEnd) const; QRegion translatedLineRegion(int lineStart, int lineEnd) const;
QPoint toolTipPosition(const QTextCursor &c) const; QPoint toolTipPosition(const QTextCursor &c) const;
void showTextMarksToolTip(const QPoint &pos,
const TextMarks &marks,
const TextMark *mainTextMark = nullptr) const;
void invokeAssist(AssistKind assistKind, IAssistProvider *provider = nullptr); void invokeAssist(AssistKind assistKind, IAssistProvider *provider = nullptr);

View File

@@ -160,7 +160,7 @@ void ValgrindTestRunnerTest::testLeak1()
QCOMPARE(error.leakedBlocks(), qint64(1)); QCOMPARE(error.leakedBlocks(), qint64(1));
QCOMPARE(error.leakedBytes(), quint64(8)); QCOMPARE(error.leakedBytes(), quint64(8));
QCOMPARE(error.stacks().count(), 1); QCOMPARE(error.stacks().count(), 1);
const Stack stack = error.stacks().first(); const Stack stack = error.stacks().constFirst();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 2); QCOMPARE(stack.frames().count(), 2);
{ {
@@ -195,7 +195,7 @@ void ValgrindTestRunnerTest::testLeak2()
QCOMPARE(error.leakedBlocks(), qint64(1)); QCOMPARE(error.leakedBlocks(), qint64(1));
QCOMPARE(error.leakedBytes(), quint64(5)); QCOMPARE(error.leakedBytes(), quint64(5));
QCOMPARE(error.stacks().count(), 1); QCOMPARE(error.stacks().count(), 1);
const Stack stack = error.stacks().first(); const Stack stack = error.stacks().constFirst();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 3); QCOMPARE(stack.frames().count(), 3);
{ {
@@ -235,7 +235,7 @@ void ValgrindTestRunnerTest::testLeak3()
QCOMPARE(error.leakedBlocks(), qint64(1)); QCOMPARE(error.leakedBlocks(), qint64(1));
QCOMPARE(error.leakedBytes(), quint64(5)); QCOMPARE(error.leakedBytes(), quint64(5));
QCOMPARE(error.stacks().count(), 1); QCOMPARE(error.stacks().count(), 1);
const Stack stack = error.stacks().first(); const Stack stack = error.stacks().constFirst();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 3); QCOMPARE(stack.frames().count(), 3);
{ {
@@ -284,7 +284,7 @@ void ValgrindTestRunnerTest::testLeak4()
QCOMPARE(error.leakedBlocks(), qint64(1)); QCOMPARE(error.leakedBlocks(), qint64(1));
QCOMPARE(error.leakedBytes(), quint64(8)); QCOMPARE(error.leakedBytes(), quint64(8));
QCOMPARE(error.stacks().count(), 1); QCOMPARE(error.stacks().count(), 1);
const Stack stack = error.stacks().first(); const Stack stack = error.stacks().constFirst();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 3); QCOMPARE(stack.frames().count(), 3);
{ {
@@ -325,7 +325,7 @@ void ValgrindTestRunnerTest::testLeak4()
else else
QCOMPARE(error.leakedBytes(), quint64(12)); QCOMPARE(error.leakedBytes(), quint64(12));
QCOMPARE(error.stacks().count(), 1); QCOMPARE(error.stacks().count(), 1);
const Stack stack = error.stacks().first(); const Stack stack = error.stacks().constFirst();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 2); QCOMPARE(stack.frames().count(), 2);
{ {
@@ -364,11 +364,11 @@ void ValgrindTestRunnerTest::testUninit1()
QCOMPARE(error.stacks().count(), 2); QCOMPARE(error.stacks().count(), 2);
//BEGIN first stack //BEGIN first stack
{ {
const Stack stack = error.stacks().first(); const Stack stack = error.stacks().constFirst();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 1); QCOMPARE(stack.frames().count(), 1);
const Frame frame = stack.frames().first(); const Frame frame = stack.frames().constFirst();
QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.functionName(), QString("main"));
QCOMPARE(frame.line(), 4 + HEADER_LENGTH); QCOMPARE(frame.line(), 4 + HEADER_LENGTH);
@@ -378,11 +378,11 @@ void ValgrindTestRunnerTest::testUninit1()
} }
//BEGIN second stack //BEGIN second stack
{ {
const Stack stack = error.stacks().last(); const Stack stack = error.stacks().constLast();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 1); QCOMPARE(stack.frames().count(), 1);
const Frame frame = stack.frames().first(); const Frame frame = stack.frames().constFirst();
QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.functionName(), QString("main"));
QCOMPARE(frame.line(), 2 + HEADER_LENGTH); QCOMPARE(frame.line(), 2 + HEADER_LENGTH);
@@ -412,11 +412,11 @@ void ValgrindTestRunnerTest::testUninit2()
QCOMPARE(error.stacks().count(), 2); QCOMPARE(error.stacks().count(), 2);
//BEGIN first stack //BEGIN first stack
{ {
const Stack stack = error.stacks().first(); const Stack stack = error.stacks().constFirst();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 1); QCOMPARE(stack.frames().count(), 1);
const Frame frame = stack.frames().first(); const Frame frame = stack.frames().constFirst();
QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.functionName(), QString("main"));
QCOMPARE(frame.line(), 4 + HEADER_LENGTH); QCOMPARE(frame.line(), 4 + HEADER_LENGTH);
@@ -426,11 +426,11 @@ void ValgrindTestRunnerTest::testUninit2()
} }
//BEGIN second stack //BEGIN second stack
{ {
const Stack stack = error.stacks().last(); const Stack stack = error.stacks().constLast();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 1); QCOMPARE(stack.frames().count(), 1);
const Frame frame = stack.frames().first(); const Frame frame = stack.frames().constFirst();
QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.functionName(), QString("main"));
QCOMPARE(frame.line(), 2 + HEADER_LENGTH); QCOMPARE(frame.line(), 2 + HEADER_LENGTH);
@@ -445,11 +445,11 @@ void ValgrindTestRunnerTest::testUninit2()
QCOMPARE(error.kind(), int(InvalidWrite)); QCOMPARE(error.kind(), int(InvalidWrite));
QCOMPARE(error.stacks().count(), 1); QCOMPARE(error.stacks().count(), 1);
const Stack stack = error.stacks().first(); const Stack stack = error.stacks().constFirst();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 1); QCOMPARE(stack.frames().count(), 1);
const Frame frame = stack.frames().first(); const Frame frame = stack.frames().constFirst();
QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.functionName(), QString("main"));
QCOMPARE(frame.line(), 4 + HEADER_LENGTH); QCOMPARE(frame.line(), 4 + HEADER_LENGTH);
@@ -479,11 +479,11 @@ void ValgrindTestRunnerTest::testUninit3()
QCOMPARE(error.stacks().count(), 2); QCOMPARE(error.stacks().count(), 2);
//BEGIN first stack //BEGIN first stack
{ {
const Stack stack = error.stacks().first(); const Stack stack = error.stacks().constFirst();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 1); QCOMPARE(stack.frames().count(), 1);
const Frame frame = stack.frames().first(); const Frame frame = stack.frames().constFirst();
QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.functionName(), QString("main"));
QCOMPARE(frame.line(), 4 + HEADER_LENGTH); QCOMPARE(frame.line(), 4 + HEADER_LENGTH);
@@ -493,11 +493,11 @@ void ValgrindTestRunnerTest::testUninit3()
} }
//BEGIN second stack //BEGIN second stack
{ {
const Stack stack = error.stacks().last(); const Stack stack = error.stacks().constLast();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 1); QCOMPARE(stack.frames().count(), 1);
const Frame frame = stack.frames().first(); const Frame frame = stack.frames().constFirst();
QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.functionName(), QString("main"));
QCOMPARE(frame.line(), 2 + HEADER_LENGTH); QCOMPARE(frame.line(), 2 + HEADER_LENGTH);
@@ -512,11 +512,11 @@ void ValgrindTestRunnerTest::testUninit3()
QCOMPARE(error.kind(), int(InvalidRead)); QCOMPARE(error.kind(), int(InvalidRead));
QCOMPARE(error.stacks().count(), 1); QCOMPARE(error.stacks().count(), 1);
const Stack stack = error.stacks().first(); const Stack stack = error.stacks().constFirst();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 1); QCOMPARE(stack.frames().count(), 1);
const Frame frame = stack.frames().first(); const Frame frame = stack.frames().constFirst();
QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.functionName(), QString("main"));
QCOMPARE(frame.line(), 4 + HEADER_LENGTH); QCOMPARE(frame.line(), 4 + HEADER_LENGTH);
@@ -543,7 +543,7 @@ void ValgrindTestRunnerTest::testSyscall()
QCOMPARE(error.stacks().count(), 2); QCOMPARE(error.stacks().count(), 2);
//BEGIN first stack //BEGIN first stack
{ {
const Stack stack = error.stacks().first(); const Stack stack = error.stacks().constFirst();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
if (on64bit()) { if (on64bit()) {
QCOMPARE(stack.frames().count(), 4); QCOMPARE(stack.frames().count(), 4);
@@ -574,11 +574,11 @@ void ValgrindTestRunnerTest::testSyscall()
} }
//BEGIN second stack //BEGIN second stack
{ {
const Stack stack = error.stacks().last(); const Stack stack = error.stacks().constLast();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 1); QCOMPARE(stack.frames().count(), 1);
const Frame frame = stack.frames().first(); const Frame frame = stack.frames().constFirst();
QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.functionName(), QString("main"));
QCOMPARE(frame.line(), 2 + HEADER_LENGTH); QCOMPARE(frame.line(), 2 + HEADER_LENGTH);
@@ -605,16 +605,16 @@ void ValgrindTestRunnerTest::testFree1()
QVERIFY(error.stacks().count() >= 2); QVERIFY(error.stacks().count() >= 2);
//BEGIN first stack //BEGIN first stack
{ {
const Stack stack = error.stacks().first(); const Stack stack = error.stacks().constFirst();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 2); QCOMPARE(stack.frames().count(), 2);
{ {
const Frame frame = stack.frames().first(); const Frame frame = stack.frames().constFirst();
QCOMPARE(frame.functionName(), QString("operator delete(void*)")); QCOMPARE(frame.functionName(), QString("operator delete(void*)"));
} }
{ {
const Frame frame = stack.frames().last(); const Frame frame = stack.frames().constLast();
QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.functionName(), QString("main"));
QCOMPARE(frame.line(), 7 + HEADER_LENGTH); QCOMPARE(frame.line(), 7 + HEADER_LENGTH);
@@ -630,11 +630,11 @@ void ValgrindTestRunnerTest::testFree1()
QCOMPARE(stack.frames().count(), 2); QCOMPARE(stack.frames().count(), 2);
{ {
const Frame frame = stack.frames().first(); const Frame frame = stack.frames().constFirst();
QCOMPARE(frame.functionName(), QString("operator delete(void*)")); QCOMPARE(frame.functionName(), QString("operator delete(void*)"));
} }
{ {
const Frame frame = stack.frames().last(); const Frame frame = stack.frames().constLast();
QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.functionName(), QString("main"));
QCOMPARE(frame.line(), 6 + HEADER_LENGTH); QCOMPARE(frame.line(), 6 + HEADER_LENGTH);
@@ -662,16 +662,16 @@ void ValgrindTestRunnerTest::testFree2()
QCOMPARE(error.stacks().count(), 2); QCOMPARE(error.stacks().count(), 2);
//BEGIN first stack //BEGIN first stack
{ {
const Stack stack = error.stacks().first(); const Stack stack = error.stacks().constFirst();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 2); QCOMPARE(stack.frames().count(), 2);
{ {
const Frame frame = stack.frames().first(); const Frame frame = stack.frames().constFirst();
QCOMPARE(frame.functionName(), QString("free")); QCOMPARE(frame.functionName(), QString("free"));
} }
{ {
const Frame frame = stack.frames().last(); const Frame frame = stack.frames().constLast();
QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.functionName(), QString("main"));
QCOMPARE(frame.line(), 6 + HEADER_LENGTH); QCOMPARE(frame.line(), 6 + HEADER_LENGTH);
@@ -682,20 +682,20 @@ void ValgrindTestRunnerTest::testFree2()
} }
//BEGIN second stack //BEGIN second stack
{ {
const Stack stack = error.stacks().last(); const Stack stack = error.stacks().constLast();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 2); QCOMPARE(stack.frames().count(), 2);
{ {
const Frame frame = stack.frames().first(); const Frame frame = stack.frames().constFirst();
if (on64bit()) if (on64bit())
QCOMPARE(frame.functionName(), QString("operator new(unsigned long)")); QCOMPARE(frame.functionName(), QString("operator new(unsigned long)"));
else else
QCOMPARE(frame.functionName(), QString("operator new(unsigned int)")); QCOMPARE(frame.functionName(), QString("operator new(unsigned int)"));
} }
{ {
const Frame frame = stack.frames().last(); const Frame frame = stack.frames().constLast();
QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.functionName(), QString("main"));
QCOMPARE(frame.line(), 5 + HEADER_LENGTH); QCOMPARE(frame.line(), 5 + HEADER_LENGTH);
@@ -721,7 +721,7 @@ void ValgrindTestRunnerTest::testInvalidjump()
const Error error = m_errors.first(); const Error error = m_errors.first();
QCOMPARE(error.kind(), int(InvalidJump)); QCOMPARE(error.kind(), int(InvalidJump));
QCOMPARE(error.stacks().count(), 1); QCOMPARE(error.stacks().count(), 1);
const Stack stack = error.stacks().first(); const Stack stack = error.stacks().constFirst();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 2); QCOMPARE(stack.frames().count(), 2);
QVERIFY(!stack.auxWhat().isEmpty()); QVERIFY(!stack.auxWhat().isEmpty());
@@ -751,7 +751,7 @@ void ValgrindTestRunnerTest::testOverlap()
const Error error = m_errors.first(); const Error error = m_errors.first();
QCOMPARE(error.kind(), int(Overlap)); QCOMPARE(error.kind(), int(Overlap));
QCOMPARE(error.stacks().count(), 1); QCOMPARE(error.stacks().count(), 1);
const Stack stack = error.stacks().first(); const Stack stack = error.stacks().constFirst();
QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.line(), qint64(-1));
QCOMPARE(stack.frames().count(), 2); QCOMPARE(stack.frames().count(), 2);
{ {
@@ -759,7 +759,7 @@ void ValgrindTestRunnerTest::testOverlap()
QVERIFY(frame.functionName().startsWith("memcpy")); QVERIFY(frame.functionName().startsWith("memcpy"));
} }
{ {
const Frame frame = stack.frames().last(); const Frame frame = stack.frames().constLast();
QCOMPARE(frame.functionName(), QLatin1String("main")); QCOMPARE(frame.functionName(), QLatin1String("main"));
QCOMPARE(frame.line(), 6 + HEADER_LENGTH); QCOMPARE(frame.line(), 6 + HEADER_LENGTH);

View File

@@ -1621,7 +1621,7 @@ Core::IEditor *VcsBaseEditor::locateEditorByTag(const QString &tag)
foreach (Core::IDocument *document, Core::DocumentModel::openedDocuments()) { foreach (Core::IDocument *document, Core::DocumentModel::openedDocuments()) {
const QVariant tagPropertyValue = document->property(tagPropertyC); const QVariant tagPropertyValue = document->property(tagPropertyC);
if (tagPropertyValue.type() == QVariant::String && tagPropertyValue.toString() == tag) if (tagPropertyValue.type() == QVariant::String && tagPropertyValue.toString() == tag)
return Core::DocumentModel::editorsForDocument(document).first(); return Core::DocumentModel::editorsForDocument(document).constFirst();
} }
return nullptr; return nullptr;
} }

View File

@@ -246,6 +246,7 @@ bool ProWriter::locateVarValues(const ushort *tokPtr, const ushort *tokPtrEnd,
struct LineInfo struct LineInfo
{ {
QString indent;
int continuationPos = 0; int continuationPos = 0;
bool hasComment = false; bool hasComment = false;
}; };
@@ -260,14 +261,29 @@ static LineInfo lineInfo(const QString &line)
li.continuationPos = idx; li.continuationPos = idx;
for (int i = idx - 1; i >= 0 && (line.at(i) == ' ' || line.at(i) == '\t'); --i) for (int i = idx - 1; i >= 0 && (line.at(i) == ' ' || line.at(i) == '\t'); --i)
--li.continuationPos; --li.continuationPos;
for (int i = 0; i < line.length() && (line.at(i) == ' ' || line.at(i) == '\t'); ++i)
li.indent += line.at(i);
return li; return li;
} }
static int skipContLines(QStringList *lines, int lineNo, bool addCont) struct ContinuationInfo {
QString indent; // Empty means use default
int lineNo;
};
static ContinuationInfo skipContLines(QStringList *lines, int lineNo, bool addCont)
{ {
bool hasConsistentIndent = true;
QString lastIndent;
for (; lineNo < lines->count(); lineNo++) { for (; lineNo < lines->count(); lineNo++) {
const QString line = lines->at(lineNo); const QString line = lines->at(lineNo);
LineInfo li = lineInfo(line); LineInfo li = lineInfo(line);
if (hasConsistentIndent) {
if (lastIndent.isEmpty())
lastIndent = li.indent;
else if (lastIndent != li.indent)
hasConsistentIndent = false;
}
if (li.continuationPos == 0) { if (li.continuationPos == 0) {
if (li.hasComment) if (li.hasComment)
continue; continue;
@@ -280,34 +296,45 @@ static int skipContLines(QStringList *lines, int lineNo, bool addCont)
break; break;
} }
} }
return lineNo; ContinuationInfo ci;
if (hasConsistentIndent)
ci.indent = lastIndent;
ci.lineNo = lineNo;
return ci;
} }
void ProWriter::putVarValues(ProFile *profile, QStringList *lines, void ProWriter::putVarValues(ProFile *profile, QStringList *lines, const QStringList &values,
const QStringList &values, const QString &var, PutFlags flags, const QString &scope) const QString &var, PutFlags flags, const QString &scope,
const QString &continuationIndent)
{ {
QString indent = scope.isEmpty() ? QString() : QLatin1String(" "); QString indent = scope.isEmpty() ? QString() : continuationIndent;
const auto effectiveContIndent = [indent, continuationIndent](const ContinuationInfo &ci) {
return !ci.indent.isEmpty() ? ci.indent : continuationIndent + indent;
};
int scopeStart = -1, lineNo; int scopeStart = -1, lineNo;
if (locateVarValues(profile->tokPtr(), profile->tokPtrEnd(), scope, var, &scopeStart, &lineNo)) { if (locateVarValues(profile->tokPtr(), profile->tokPtrEnd(), scope, var, &scopeStart, &lineNo)) {
if (flags & ReplaceValues) { if (flags & ReplaceValues) {
// remove continuation lines with old values // remove continuation lines with old values
int lNo = skipContLines(lines, lineNo, false); const ContinuationInfo contInfo = skipContLines(lines, lineNo, false);
lines->erase(lines->begin() + lineNo + 1, lines->begin() + lNo); lines->erase(lines->begin() + lineNo + 1, lines->begin() + contInfo.lineNo);
// remove rest of the line // remove rest of the line
QString &line = (*lines)[lineNo]; QString &line = (*lines)[lineNo];
int eqs = line.indexOf(QLatin1Char('=')); int eqs = line.indexOf(QLatin1Char('='));
if (eqs >= 0) // If this is not true, we mess up the file a bit. if (eqs >= 0) // If this is not true, we mess up the file a bit.
line.truncate(eqs + 1); line.truncate(eqs + 1);
// put new values // put new values
foreach (const QString &v, values) foreach (const QString &v, values) {
line += ((flags & MultiLine) ? QLatin1String(" \\\n ") + indent : QString::fromLatin1(" ")) + v; line += ((flags & MultiLine) ? QLatin1String(" \\\n") + effectiveContIndent(contInfo)
: QString::fromLatin1(" ")) + v;
}
} else { } else {
int endLineNo = skipContLines(lines, lineNo, false); const ContinuationInfo contInfo = skipContLines(lines, lineNo, false);
int endLineNo = contInfo.lineNo;
for (const QString &v : values) { for (const QString &v : values) {
int curLineNo = lineNo + 1; int curLineNo = lineNo + 1;
while (curLineNo < endLineNo && v >= lines->at(curLineNo).trimmed()) while (curLineNo < endLineNo && v >= lines->at(curLineNo).trimmed())
++curLineNo; ++curLineNo;
QString newLine = " " + indent + v; QString newLine = effectiveContIndent(contInfo) + v;
if (curLineNo == endLineNo) { if (curLineNo == endLineNo) {
QString &oldLastLine = (*lines)[endLineNo - 1]; QString &oldLastLine = (*lines)[endLineNo - 1];
oldLastLine.insert(lineInfo(oldLastLine).continuationPos, " \\"); oldLastLine.insert(lineInfo(oldLastLine).continuationPos, " \\");
@@ -322,6 +349,7 @@ void ProWriter::putVarValues(ProFile *profile, QStringList *lines,
// Create & append new variable item // Create & append new variable item
QString added; QString added;
int lNo = lines->count(); int lNo = lines->count();
ContinuationInfo contInfo;
if (!scope.isEmpty()) { if (!scope.isEmpty()) {
if (scopeStart < 0) { if (scopeStart < 0) {
added = QLatin1Char('\n') + scope + QLatin1String(" {"); added = QLatin1Char('\n') + scope + QLatin1String(" {");
@@ -329,8 +357,10 @@ void ProWriter::putVarValues(ProFile *profile, QStringList *lines,
QRegExp rx(QLatin1String("(\\s*") + scope + QLatin1String("\\s*:\\s*)[^\\s{].*")); QRegExp rx(QLatin1String("(\\s*") + scope + QLatin1String("\\s*:\\s*)[^\\s{].*"));
if (rx.exactMatch(lines->at(scopeStart))) { if (rx.exactMatch(lines->at(scopeStart))) {
(*lines)[scopeStart].replace(0, rx.cap(1).length(), (*lines)[scopeStart].replace(0, rx.cap(1).length(),
QString(scope + QLatin1String(" {\n "))); QString(scope + QLatin1String(" {\n")
lNo = skipContLines(lines, scopeStart, false); + continuationIndent));
contInfo = skipContLines(lines, scopeStart, false);
lNo = contInfo.lineNo;
scopeStart = -1; scopeStart = -1;
} }
} }
@@ -357,14 +387,16 @@ void ProWriter::putVarValues(ProFile *profile, QStringList *lines,
added += QLatin1Char('\n'); added += QLatin1Char('\n');
added += indent + var + QLatin1String((flags & AppendOperator) ? " +=" : " ="); added += indent + var + QLatin1String((flags & AppendOperator) ? " +=" : " =");
foreach (const QString &v, values) foreach (const QString &v, values)
added += ((flags & MultiLine) ? QLatin1String(" \\\n ") + indent : QString::fromLatin1(" ")) + v; added += ((flags & MultiLine) ? QLatin1String(" \\\n") + effectiveContIndent(contInfo)
: QString::fromLatin1(" ")) + v;
if (!scope.isEmpty() && scopeStart < 0) if (!scope.isEmpty() && scopeStart < 0)
added += QLatin1String("\n}"); added += QLatin1String("\n}");
lines->insert(lNo, added); lines->insert(lNo, added);
} }
} }
void ProWriter::addFiles(ProFile *profile, QStringList *lines, const QStringList &values, const QString &var) void ProWriter::addFiles(ProFile *profile, QStringList *lines, const QStringList &values,
const QString &var, const QString &continuationIndent)
{ {
QStringList valuesToWrite; QStringList valuesToWrite;
QString prefixPwd; QString prefixPwd;
@@ -374,7 +406,8 @@ void ProWriter::addFiles(ProFile *profile, QStringList *lines, const QStringList
foreach (const QString &v, values) foreach (const QString &v, values)
valuesToWrite << (prefixPwd + baseDir.relativeFilePath(v)); valuesToWrite << (prefixPwd + baseDir.relativeFilePath(v));
putVarValues(profile, lines, valuesToWrite, var, AppendValues | MultiLine | AppendOperator); putVarValues(profile, lines, valuesToWrite, var, AppendValues | MultiLine | AppendOperator,
QString(), continuationIndent);
} }
static void findProVariables(const ushort *tokPtr, const QStringList &vars, static void findProVariables(const ushort *tokPtr, const QStringList &vars,

View File

@@ -51,11 +51,12 @@ public:
static void putVarValues(ProFile *profile, QStringList *lines, static void putVarValues(ProFile *profile, QStringList *lines,
const QStringList &values, const QString &var, PutFlags flags, const QStringList &values, const QString &var, PutFlags flags,
const QString &scope = QString()); const QString &scope, const QString &continuationIndent);
static QList<int> removeVarValues(ProFile *profile, QStringList *lines, static QList<int> removeVarValues(ProFile *profile, QStringList *lines,
const QStringList &values, const QStringList &vars); const QStringList &values, const QStringList &vars);
static void addFiles(ProFile *profile, QStringList *lines, const QStringList &filePaths, const QString &var); static void addFiles(ProFile *profile, QStringList *lines, const QStringList &filePaths,
const QString &var, const QString &continuationIndent);
static QStringList removeFiles(ProFile *profile, QStringList *lines, static QStringList removeFiles(ProFile *profile, QStringList *lines,
const QDir &proFileDir, const QStringList &filePaths, const QStringList &vars); const QDir &proFileDir, const QStringList &filePaths, const QStringList &vars);

View File

@@ -102,7 +102,7 @@ void tst_ProFileWriter::adds_data()
"add new append multi", f_foo, 0, "add new append multi", f_foo, 0,
"", "",
"SOURCES += \\\n" "SOURCES += \\\n"
" foo" "\tfoo"
}, },
{ {
PW::AppendValues|PW::AppendOperator|PW::MultiLine, PW::AppendValues|PW::AppendOperator|PW::MultiLine,
@@ -111,7 +111,7 @@ void tst_ProFileWriter::adds_data()
"# test file\n" "# test file\n"
"\n" "\n"
"SOURCES += \\\n" "SOURCES += \\\n"
" foo" "\tfoo"
}, },
{ {
PW::AppendValues|PW::AppendOperator|PW::MultiLine, PW::AppendValues|PW::AppendOperator|PW::MultiLine,
@@ -120,7 +120,7 @@ void tst_ProFileWriter::adds_data()
"\n" "\n"
"\n", "\n",
"SOURCES += \\\n" "SOURCES += \\\n"
" foo\n" "\tfoo\n"
"\n" "\n"
"\n" "\n"
"\n" "\n"
@@ -135,7 +135,7 @@ void tst_ProFileWriter::adds_data()
"# test file\n" "# test file\n"
"\n" "\n"
"SOURCES += \\\n" "SOURCES += \\\n"
" foo\n" "\tfoo\n"
"\n" "\n"
"\n" "\n"
"\n" "\n"
@@ -147,7 +147,7 @@ void tst_ProFileWriter::adds_data()
"# test file\n" "# test file\n"
"\n" "\n"
"SOURCES = \\\n" "SOURCES = \\\n"
" foo" "\tfoo"
}, },
{ {
PW::AppendValues|PW::AppendOperator|PW::OneLine, PW::AppendValues|PW::AppendOperator|PW::OneLine,
@@ -184,43 +184,43 @@ void tst_ProFileWriter::adds_data()
"unix:SOURCES = some files\n" "unix:SOURCES = some files\n"
"\n" "\n"
"SOURCES += \\\n" "SOURCES += \\\n"
" foo" "\tfoo"
}, },
{ {
PW::AppendValues|PW::AppendOperator|PW::MultiLine, PW::AppendValues|PW::AppendOperator|PW::MultiLine,
"add new after some scope", f_foo, 0, "add new after some scope", f_foo, 0,
"unix {\n" "unix {\n"
" SOMEVAR = foo\n" "\tSOMEVAR = foo\n"
"}", "}",
"unix {\n" "unix {\n"
" SOMEVAR = foo\n" "\tSOMEVAR = foo\n"
"}\n" "}\n"
"\n" "\n"
"SOURCES += \\\n" "SOURCES += \\\n"
" foo" "\tfoo"
}, },
{ {
PW::AppendValues|PW::AppendOperator|PW::MultiLine, PW::AppendValues|PW::AppendOperator|PW::MultiLine,
"add to existing (wrong operator)", f_foo, 0, "add to existing (wrong operator)", f_foo, 0,
"SOURCES = some files", "SOURCES = some files",
"SOURCES = some files \\\n" "SOURCES = some files \\\n"
" foo" "\tfoo"
}, },
{ {
PW::AppendValues|PW::AppendOperator|PW::MultiLine, PW::AppendValues|PW::AppendOperator|PW::MultiLine,
"insert at end", f_foo_bar, 0, "insert at end", f_foo_bar, 0,
"SOURCES = some files", "SOURCES = some files",
"SOURCES = some files \\\n" "SOURCES = some files \\\n"
" bar \\\n" "\tbar \\\n"
" foo" "\tfoo"
}, },
{ {
PW::AppendValues|PW::AppendOperator|PW::MultiLine, PW::AppendValues|PW::AppendOperator|PW::MultiLine,
"insert into empty", f_foo_bar, 0, "insert into empty", f_foo_bar, 0,
"SOURCES =", "SOURCES =",
"SOURCES = \\\n" "SOURCES = \\\n"
" bar \\\n" "\tbar \\\n"
" foo" "\tfoo"
}, },
{ {
PW::AppendValues|PW::AppendOperator|PW::MultiLine, PW::AppendValues|PW::AppendOperator|PW::MultiLine,
@@ -239,33 +239,33 @@ void tst_ProFileWriter::adds_data()
"add to existing after comment (wrong operator)", f_foo, 0, "add to existing after comment (wrong operator)", f_foo, 0,
"SOURCES = some files # comment", "SOURCES = some files # comment",
"SOURCES = some files \\ # comment\n" "SOURCES = some files \\ # comment\n"
" foo" "\tfoo"
}, },
{ {
PW::AppendValues|PW::AppendOperator|PW::MultiLine, PW::AppendValues|PW::AppendOperator|PW::MultiLine,
"add to existing after comment line (wrong operator)", f_foo, 0, "add to existing after comment line (wrong operator)", f_foo, 0,
"SOURCES = some \\\n" "SOURCES = some \\\n"
" # comment\n" " # comment\n"
" files", "\tfiles",
"SOURCES = some \\\n" "SOURCES = some \\\n"
" # comment\n" " # comment\n"
" files \\\n" "\tfiles \\\n"
" foo" "\tfoo"
}, },
{ {
PW::AppendValues|PW::AssignOperator|PW::MultiLine, PW::AppendValues|PW::AssignOperator|PW::MultiLine,
"add to existing", f_foo, 0, "add to existing", f_foo, 0,
"SOURCES = some files", "SOURCES = some files",
"SOURCES = some files \\\n" "SOURCES = some files \\\n"
" foo" "\tfoo"
}, },
{ {
PW::ReplaceValues|PW::AssignOperator|PW::MultiLine, PW::ReplaceValues|PW::AssignOperator|PW::MultiLine,
"replace existing multi", f_foo_bar, 0, "replace existing multi", f_foo_bar, 0,
"SOURCES = some files", "SOURCES = some files",
"SOURCES = \\\n" "SOURCES = \\\n"
" foo \\\n" "\tfoo \\\n"
" bar" "\tbar"
}, },
{ {
PW::ReplaceValues|PW::AssignOperator|PW::OneLine, PW::ReplaceValues|PW::AssignOperator|PW::OneLine,
@@ -278,7 +278,7 @@ void tst_ProFileWriter::adds_data()
"replace existing complex last", f_foo_bar, 0, "replace existing complex last", f_foo_bar, 0,
"SOURCES = some \\\n" "SOURCES = some \\\n"
" # comment\n" " # comment\n"
" files", "\tfiles",
"SOURCES = foo bar" "SOURCES = foo bar"
}, },
{ {
@@ -286,7 +286,7 @@ void tst_ProFileWriter::adds_data()
"replace existing complex middle 1", f_foo_bar, 0, "replace existing complex middle 1", f_foo_bar, 0,
"SOURCES = some \\\n" "SOURCES = some \\\n"
" # comment\n" " # comment\n"
" files\n" "\tfiles\n"
"HEADERS = blubb", "HEADERS = blubb",
"SOURCES = foo bar\n" "SOURCES = foo bar\n"
"HEADERS = blubb" "HEADERS = blubb"
@@ -296,7 +296,7 @@ void tst_ProFileWriter::adds_data()
"replace existing complex middle 2", f_foo_bar, 0, "replace existing complex middle 2", f_foo_bar, 0,
"SOURCES = some \\\n" "SOURCES = some \\\n"
" # comment\n" " # comment\n"
" files\n" "\tfiles\n"
"\n" "\n"
"HEADERS = blubb", "HEADERS = blubb",
"SOURCES = foo bar\n" "SOURCES = foo bar\n"
@@ -308,7 +308,7 @@ void tst_ProFileWriter::adds_data()
"replace existing complex middle 3", f_foo_bar, 0, "replace existing complex middle 3", f_foo_bar, 0,
"SOURCES = some \\\n" "SOURCES = some \\\n"
" # comment\n" " # comment\n"
" files \\\n" "\tfiles \\\n"
"\n" "\n"
"HEADERS = blubb", "HEADERS = blubb",
"SOURCES = foo bar\n" "SOURCES = foo bar\n"
@@ -324,7 +324,7 @@ void tst_ProFileWriter::adds_data()
"SOURCES = yo\n" "SOURCES = yo\n"
"\n" "\n"
"dog {\n" "dog {\n"
" SOURCES += foo\n" "\tSOURCES += foo\n"
"}" "}"
}, },
{ {
@@ -332,13 +332,13 @@ void tst_ProFileWriter::adds_data()
"scoped new / extend scope", f_foo, "dog", "scoped new / extend scope", f_foo, "dog",
"# test file\n" "# test file\n"
"dog {\n" "dog {\n"
" HEADERS += yo\n" "\tHEADERS += yo\n"
"}", "}",
"# test file\n" "# test file\n"
"dog {\n" "dog {\n"
" HEADERS += yo\n" "\tHEADERS += yo\n"
"\n" "\n"
" SOURCES += foo\n" "\tSOURCES += foo\n"
"}" "}"
}, },
{ {
@@ -356,7 +356,7 @@ void tst_ProFileWriter::adds_data()
" yo \\\n" " yo \\\n"
" blubb\n" " blubb\n"
"\n" "\n"
" SOURCES += foo\n" "\tSOURCES += foo\n"
"}" "}"
}, },
{ {
@@ -367,7 +367,7 @@ void tst_ProFileWriter::adds_data()
"}", "}",
"# test file\n" "# test file\n"
"dog {\n" "dog {\n"
" SOURCES += foo\n" "\tSOURCES += foo\n"
"}" "}"
}, },
{ {
@@ -377,9 +377,9 @@ void tst_ProFileWriter::adds_data()
"dog:HEADERS += yo", "dog:HEADERS += yo",
"# test file\n" "# test file\n"
"dog {\n" "dog {\n"
" HEADERS += yo\n" "\tHEADERS += yo\n"
"\n" "\n"
" SOURCES += foo\n" "\tSOURCES += foo\n"
"}" "}"
}, },
{ {
@@ -392,10 +392,10 @@ void tst_ProFileWriter::adds_data()
"blubb()", "blubb()",
"# test file\n" "# test file\n"
"dog {\n" "dog {\n"
" HEADERS += yo \\\n" "\tHEADERS += yo \\\n"
" you\n" " you\n"
"\n" "\n"
" SOURCES += foo\n" "\tSOURCES += foo\n"
"}\n" "}\n"
"\n" "\n"
"blubb()" "blubb()"
@@ -413,8 +413,8 @@ void tst_ProFileWriter::adds_data()
" SOMEVAR = foo\n" " SOMEVAR = foo\n"
" }\n" " }\n"
"\n" "\n"
" SOURCES += \\\n" "\tSOURCES += \\\n"
" foo\n" "\t\tfoo\n"
"}" "}"
}, },
{ {
@@ -425,7 +425,7 @@ void tst_ProFileWriter::adds_data()
"}", "}",
"# test file\n" "# test file\n"
"dog: {\n" "dog: {\n"
" SOURCES += foo\n" "\tSOURCES += foo\n"
"}" "}"
}, },
{ {
@@ -435,7 +435,7 @@ void tst_ProFileWriter::adds_data()
"dog:SOURCES = yo", "dog:SOURCES = yo",
"# test file\n" "# test file\n"
"dog:SOURCES = yo \\\n" "dog:SOURCES = yo \\\n"
" foo" "\t\tfoo"
}, },
{ {
PW::AppendValues|PW::AppendOperator|PW::MultiLine, PW::AppendValues|PW::AppendOperator|PW::MultiLine,
@@ -446,8 +446,8 @@ void tst_ProFileWriter::adds_data()
"animal:!dog:SOURCES = yo\n" "animal:!dog:SOURCES = yo\n"
"\n" "\n"
"dog {\n" "dog {\n"
" SOURCES += \\\n" "\tSOURCES += \\\n"
" foo\n" "\t\tfoo\n"
"}" "}"
}, },
}; };
@@ -478,7 +478,7 @@ void tst_ProFileWriter::adds()
QMakeParser parser(0, &vfs, &parseHandler); QMakeParser parser(0, &vfs, &parseHandler);
ProFile *proFile = parser.parsedProBlock(QStringRef(&input), 0, QLatin1String(BASE_DIR "/test.pro"), 1); ProFile *proFile = parser.parsedProBlock(QStringRef(&input), 0, QLatin1String(BASE_DIR "/test.pro"), 1);
QVERIFY(proFile); QVERIFY(proFile);
PW::putVarValues(proFile, &lines, values, var, PW::PutFlags(flags), scope); PW::putVarValues(proFile, &lines, values, var, PW::PutFlags(flags), scope, "\t");
proFile->deref(); proFile->deref();
QCOMPARE(lines.join(QLatin1Char('\n')), output); QCOMPARE(lines.join(QLatin1Char('\n')), output);
@@ -692,7 +692,7 @@ void tst_ProFileWriter::addFiles()
QStringList lines = input.split(QLatin1Char('\n')); QStringList lines = input.split(QLatin1Char('\n'));
QString output = QLatin1String( QString output = QLatin1String(
"SOURCES = foo.cpp \\\n" "SOURCES = foo.cpp \\\n"
" sub/bar.cpp" "\tsub/bar.cpp"
); );
QMakeVfs vfs; QMakeVfs vfs;
@@ -701,7 +701,7 @@ void tst_ProFileWriter::addFiles()
QVERIFY(proFile); QVERIFY(proFile);
QmakeProjectManager::Internal::ProWriter::addFiles(proFile, &lines, QmakeProjectManager::Internal::ProWriter::addFiles(proFile, &lines,
QStringList() << QString::fromLatin1(BASE_DIR "/sub/bar.cpp"), QStringList() << QString::fromLatin1(BASE_DIR "/sub/bar.cpp"),
QLatin1String("SOURCES")); QLatin1String("SOURCES"), "\t");
proFile->deref(); proFile->deref();
QCOMPARE(lines.join(QLatin1Char('\n')), output); QCOMPARE(lines.join(QLatin1Char('\n')), output);

View File

@@ -98,6 +98,22 @@ TEST_F(CompilerOptionsBuilder, CompilerFlagsFiltering_UnknownOptionsAreForwarded
ASSERT_THAT(compilerOptionsBuilder.options(), Contains(part.compilerFlags.first())); ASSERT_THAT(compilerOptionsBuilder.options(), Contains(part.compilerFlags.first()));
} }
TEST_F(CompilerOptionsBuilder, CompilerFlagsFiltering_WarningsFlagsAreNotFilteredIfRequested)
{
ProjectPart part = projectPart;
part.compilerFlags = QStringList{"-Whello"};
CppTools::CompilerOptionsBuilder compilerOptionsBuilder{part,
CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::No,
CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::Yes};
compilerOptionsBuilder.build(ProjectFile::CXXSource, CppTools::UsePrecompiledHeaders::No);
ASSERT_THAT(compilerOptionsBuilder.options(), Contains(part.compilerFlags.first()));
}
TEST_F(CompilerOptionsBuilder, CompilerFlagsFiltering_DiagnosticOptionsAreRemoved) TEST_F(CompilerOptionsBuilder, CompilerFlagsFiltering_DiagnosticOptionsAreRemoved)
{ {
ProjectPart part = projectPart; ProjectPart part = projectPart;
@@ -171,6 +187,7 @@ TEST_F(CompilerOptionsBuilder, HeaderPathOptionsOrder)
CppTools::UseSystemHeader::No, CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No, CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version", "dummy_version",
""}; ""};
@@ -196,6 +213,7 @@ TEST_F(CompilerOptionsBuilder, HeaderPathOptionsOrderCl)
CppTools::UseSystemHeader::No, CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No, CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version", "dummy_version",
""}; ""};
compilerOptionsBuilder.evaluateCompilerFlags(); compilerOptionsBuilder.evaluateCompilerFlags();
@@ -221,6 +239,7 @@ TEST_F(CompilerOptionsBuilder, UseSystemHeader)
CppTools::UseSystemHeader::Yes, CppTools::UseSystemHeader::Yes,
CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No, CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version", "dummy_version",
""}; ""};
@@ -265,6 +284,7 @@ TEST_F(CompilerOptionsBuilder, ClangHeadersAndCppIncludesPathsOrderMacOs)
CppTools::UseSystemHeader::No, CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No, CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version", "dummy_version",
""); "");
@@ -310,6 +330,7 @@ TEST_F(CompilerOptionsBuilder, ClangHeadersAndCppIncludesPathsOrderLinux)
CppTools::UseSystemHeader::No, CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No, CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version", "dummy_version",
""); "");
@@ -356,6 +377,7 @@ TEST_F(CompilerOptionsBuilder, ClangHeadersAndCppIncludesPathsOrderNoVersion)
CppTools::UseSystemHeader::No, CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No, CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version", "dummy_version",
""); "");
@@ -403,6 +425,7 @@ TEST_F(CompilerOptionsBuilder, ClangHeadersAndCppIncludesPathsOrderAndroidClang)
CppTools::UseSystemHeader::No, CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No, CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version", "dummy_version",
""); "");
@@ -480,6 +503,7 @@ TEST_F(CompilerOptionsBuilder, InsertWrappedQtHeaders)
CppTools::UseSystemHeader::Yes, CppTools::UseSystemHeader::Yes,
CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No, CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version", "dummy_version",
""}; ""};
@@ -613,6 +637,7 @@ TEST_F(CompilerOptionsBuilder, BuildAllOptions)
CppTools::UseSystemHeader::No, CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No, CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version", "dummy_version",
""); "");
@@ -652,6 +677,7 @@ TEST_F(CompilerOptionsBuilder, BuildAllOptionsCl)
CppTools::UseSystemHeader::No, CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No, CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version", "dummy_version",
""); "");