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
/.qmake.cache
/.qmake.stash
.qmake.cache
.qmake.stash
Makefile*
Thumbs.db
core

View File

@@ -656,7 +656,9 @@ QObject *ObjectNodeInstance::createPrimitiveFromSource(const QString &typeName,
if (parts.isEmpty())
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";
return createCustomParserObject(source, "", context);
}

View File

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

View File

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

View File

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

View File

@@ -24,9 +24,12 @@
****************************************************************************/
#include "autotesticons.h"
#include "autotestplugin.h"
#include "testresultdelegate.h"
#include "testresultmodel.h"
#include "testsettings.h"
#include <projectexplorer/projectexplorericons.h>
#include <utils/qtcassert.h>
#include <QFontMetrics>
@@ -62,6 +65,7 @@ static QIcon testResultIcon(Result::Type result) {
QIcon(),
Icons::RESULT_MESSAGEPASSWARN.icon(),
Icons::RESULT_MESSAGEFAILWARN.icon(),
ProjectExplorer::Icons::DESKTOP_DEVICE.icon(), // for now
}; // provide an icon for unknown??
if (result < 0 || result >= Result::MessageInternal) {
@@ -74,6 +78,8 @@ static QIcon testResultIcon(Result::Type result) {
return icons[16];
case Result::MessageTestCaseFailWarn:
return icons[17];
case Result::Application:
return icons[18];
default:
return QIcon();
}
@@ -224,7 +230,32 @@ void TestResultModel::addTestResult(const TestResultPtr &testResult, bool autoEx
m_testResultCount[testResult->result()]++;
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
if (parentItem) {
parentItem->appendChild(newItem);
@@ -373,7 +404,7 @@ void TestResultFilterModel::enableAllResultTypes()
<< Result::MessageTestCaseSuccess << Result::MessageTestCaseSuccessWarn
<< Result::MessageTestCaseFail << Result::MessageTestCaseFailWarn
<< Result::MessageTestCaseEnd
<< Result::MessageInfo << Result::MessageSystem;
<< Result::MessageInfo << Result::MessageSystem << Result::Application;
invalidateFilter();
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -210,36 +210,6 @@ bool isDiagnosticAtLocation(const ClangBackEnd::DiagnosticContainer &diagnostic,
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)
{
const QTextBlock textBlock = textDocument->findBlockByNumber(lineNumber - 1);
@@ -399,24 +369,16 @@ TextEditor::RefactorMarkers ClangDiagnosticManager::takeFixItAvailableMarkers()
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)
|| editorDocumentProcessorHasDiagnosticAt(m_warningDiagnostics, line, column, textDocument);
for (ClangTextMark *textMark : m_clangTextMarks) {
if (isDiagnosticAtLocation(textMark->diagnostic(), line, column, m_textDocument->document()))
textMarks << textMark;
}
QVector<ClangBackEnd::DiagnosticContainer>
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;
return textMarks;
}
void ClangDiagnosticManager::invalidateDiagnostics()

View File

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

View File

@@ -25,6 +25,7 @@
#include "clangdiagnostictooltipwidget.h"
#include "clangfixitoperation.h"
#include "clangutils.h"
#include <coreplugin/editormanager/editormanager.h>
@@ -149,7 +150,7 @@ public:
QTC_CHECK(!"Link target cannot be handled.");
if (hideToolTipAfterLinkActivation)
Utils::ToolTip::hideImmediately();
::Utils::ToolTip::hideImmediately();
});
return label;
@@ -171,50 +172,6 @@ public:
private:
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
// we will conclude them from the diagnostic message.
//
@@ -233,6 +190,7 @@ private:
ClangBackEnd::DiagnosticContainer supplementedDiagnostic = diagnostic;
using namespace ClangCodeModel::Utils;
DiagnosticTextInfo info(diagnostic.text);
supplementedDiagnostic.enableOption = info.option();
supplementedDiagnostic.category = info.category();
@@ -269,7 +227,7 @@ private:
QString option = optionAsUtf8String.toString();
// Clazy
if (isClazyOption(option)) {
if (ClangCodeModel::Utils::DiagnosticTextInfo::isClazyOption(option)) {
option = optionAsUtf8String.mid(8); // Remove "-Wclazy-" prefix.
return QString::fromUtf8(CLAZY_DOCUMENTATION_URL_TEMPLATE).arg(option);
}

View File

@@ -48,7 +48,6 @@
#include <cpptools/cppworkingcopy.h>
#include <cpptools/editordocumenthandle.h>
#include <texteditor/displaysettings.h>
#include <texteditor/fontsettings.h>
#include <texteditor/texteditor.h>
#include <texteditor/texteditorconstants.h>
@@ -292,27 +291,6 @@ TextEditor::QuickFixOperations ClangEditorDocumentProcessor::extraRefactoringOpe
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()
{
m_updateBackendDocumentTimer.stop(); // Wait for the next call to run().
@@ -323,6 +301,12 @@ void ClangEditorDocumentProcessor::invalidateDiagnostics()
m_diagnosticManager.invalidateDiagnostics();
}
TextEditor::TextMarks ClangEditorDocumentProcessor::diagnosticTextMarksAt(uint line,
uint column) const
{
return m_diagnosticManager.diagnosticTextMarksAt(line, column);
}
void ClangEditorDocumentProcessor::setParserConfig(
const CppTools::BaseEditorDocumentParser::Configuration &config)
{
@@ -468,6 +452,10 @@ public:
const QStringList &options() const { return m_options; }
const Core::Id &diagnosticConfigId() const { return m_diagnosticConfigId; }
CppTools::UseBuildSystemWarnings useBuildSystemWarnings() const
{
return m_useBuildSystemWarnings;
}
private:
void addLanguageOptions()
@@ -507,6 +495,9 @@ private:
void addDiagnosticOptionsForConfig(const CppTools::ClangDiagnosticConfig &diagnosticConfig)
{
m_diagnosticConfigId = diagnosticConfig.id();
m_useBuildSystemWarnings = diagnosticConfig.useBuildSystemWarnings()
? CppTools::UseBuildSystemWarnings::Yes
: CppTools::UseBuildSystemWarnings::No;
m_options.append(diagnosticConfig.clangOptions());
addClangTidyOptions(diagnosticConfig);
@@ -581,6 +572,7 @@ private:
const CppTools::ProjectPart &m_projectPart;
Core::Id m_diagnosticConfigId;
CppTools::UseBuildSystemWarnings m_useBuildSystemWarnings = CppTools::UseBuildSystemWarnings::No;
CppTools::CompilerOptionsBuilder m_builder;
QStringList m_options;
};
@@ -602,13 +594,13 @@ void ClangEditorDocumentProcessor::updateBackendDocument(CppTools::ProjectPart &
return;
}
const QStringList projectPartOptions = ClangCodeModel::Utils::createClangOptions(
projectPart,
CppTools::ProjectFile::Unsupported); // No language option as FileOptionsBuilder adds it.
const FileOptionsBuilder fileOptions(filePath(), projectPart);
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();
m_communicator.documentsOpened(

View File

@@ -83,8 +83,8 @@ public:
extraRefactoringOperations(const TextEditor::AssistInterface &assistInterface) 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;

View File

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

View File

@@ -27,11 +27,20 @@
#include "clangconstants.h"
#include "clangdiagnostictooltipwidget.h"
#include "clangeditordocumentprocessor.h"
#include "clangmodelmanagersupport.h"
#include "clangprojectsettings.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/theme/theme.h>
#include <utils/utilsicons.h>
#include <QAction>
#include <QApplication>
@@ -64,6 +73,102 @@ static Core::Id categoryForSeverity(ClangBackEnd::DiagnosticSeverity severity)
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
ClangTextMark::ClangTextMark(const FileName &fileName,
@@ -88,6 +193,8 @@ ClangTextMark::ClangTextMark(const FileName &fileName,
: ::Utils::Theme::CodeModel_Error_TextMarkColor);
}
// Copy to clipboard action
QVector<QAction *> actions;
QAction *action = new QAction();
action->setIcon(QIcon::fromTheme("edit-copy", ::Utils::Icons::COPY.icon()));
QObject::connect(action, &QAction::triggered, [diagnostic]() {
@@ -96,7 +203,19 @@ ClangTextMark::ClangTextMark(const FileName &fileName,
ClangDiagnosticWidget::InfoBar);
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)

View File

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

View File

@@ -66,11 +66,13 @@ namespace Utils {
class LibClangOptionsBuilder final : public CompilerOptionsBuilder
{
public:
LibClangOptionsBuilder(const ProjectPart &projectPart)
LibClangOptionsBuilder(const ProjectPart &projectPart,
UseBuildSystemWarnings useBuildSystemWarnings)
: CompilerOptionsBuilder(projectPart,
UseSystemHeader::No,
UseTweakedHeaderPaths::Yes,
UseLanguageDefines::No,
useBuildSystemWarnings,
QString(CLANG_VERSION),
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)
@@ -368,5 +373,51 @@ QString currentCppEditorDocumentFilePath()
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 Clang

View File

@@ -28,6 +28,7 @@
#include <cplusplus/Icons.h>
#include <cpptools/projectpart.h>
#include <cpptools/compileroptionsbuilder.h>
#include <QTextCursor>
@@ -53,6 +54,7 @@ CppTools::CppEditorDocumentHandle *cppDocument(const QString &filePath);
void setLastSentDocumentRevision(const QString &filePath, uint revision);
QStringList createClangOptions(const CppTools::ProjectPart &projectPart,
CppTools::UseBuildSystemWarnings useBuildSystemWarnings,
CppTools::ProjectFile::Kind fileKind);
CppTools::ProjectPart::Ptr projectPartForFile(const QString &filePath);
@@ -70,6 +72,23 @@ QString diagnosticCategoryPrefixRemoved(const QString &text);
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 {
template <class CharacterProvider>

View File

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

View File

@@ -223,7 +223,7 @@ bool PreconfiguredSessionTests::switchToProjectAndTarget(Project *project,
SessionManager::setActiveTarget(project, target, ProjectExplorer::SetActive::NoCascade);
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);
return projectArgument.value<ProjectExplorer::Project *>() == project;

View File

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

View File

@@ -102,7 +102,7 @@ QT_BEGIN_NAMESPACE
namespace QTest {
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();
}
bool BaseEditorDocumentProcessor::hasDiagnosticsAt(uint, uint) const
{
return false;
}
void BaseEditorDocumentProcessor::addDiagnosticToolTipToLayout(uint, uint, QLayout *) const
{
}
void BaseEditorDocumentProcessor::editorDocumentTimerRestarted()
{
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -38,6 +38,7 @@
#include <projectexplorer/selectablefilesmodel.h>
#include <utils/algorithm.h>
#include <utils/executeondestruction.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
@@ -318,16 +319,6 @@ public:
m_root->checked = Qt::Unchecked;
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) {
const QModelIndex index = indexForCheck(check);
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 {
if (check == "*")
return index(0, 0, QModelIndex());
@@ -536,7 +510,7 @@ public:
const auto *node = ClazyChecksTree::fromIndex(index);
if (node->kind == ClazyChecksTree::CheckNode) {
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);
});
}
@@ -611,7 +585,7 @@ ClangDiagnosticConfigsWidget::ClangDiagnosticConfigsWidget(const Core::Id &confi
this, &ClangDiagnosticConfigsWidget::onCopyButtonClicked);
connect(m_ui->removeButton, &QPushButton::clicked,
this, &ClangDiagnosticConfigsWidget::onRemoveButtonClicked);
connectDiagnosticOptionsChanged();
connectClangOnlyOptionsChanged();
connect(m_tidyChecks->checksPrefixesTree,
&QTreeView::clicked,
@@ -734,14 +708,17 @@ static QStringList normalizeDiagnosticInputOptions(const QString &options)
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()
->toPlainText();
const QStringList normalizedOptions = normalizeDiagnosticInputOptions(diagnosticOptions);
// Validate
// Validate options input
const QString errorMessage = validateDiagnosticOptions(normalizedOptions);
updateValidityWidgets(errorMessage);
if (!errorMessage.isEmpty()) {
@@ -754,6 +731,7 @@ void ClangDiagnosticConfigsWidget::onDiagnosticOptionsEdited()
// Commit valid changes
ClangDiagnosticConfig updatedConfig = selectedConfig();
updatedConfig.setClangOptions(normalizedOptions);
updatedConfig.setUseBuildSystemWarnings(useBuildSystemWarnings);
updateConfig(updatedConfig);
}
@@ -793,11 +771,17 @@ void ClangDiagnosticConfigsWidget::syncOtherWidgetsToComboBox()
if (isConfigChooserEmpty())
return;
disconnectClangOnlyOptionsChanged();
Utils::ExecuteOnDestruction e([this]() { connectClangOnlyOptionsChanged(); });
const ClangDiagnosticConfig &config = selectedConfig();
// Update main button row
m_ui->removeButton->setEnabled(!config.isReadOnly());
// Update check box
m_clangBaseChecks->useFlagsFromBuildSystemCheckBox->setChecked(config.useBuildSystemWarnings());
// Update Text Edit
const QString options = m_notAcceptedOptions.contains(config.id())
? m_notAcceptedOptions.value(config.id())
@@ -894,11 +878,8 @@ bool ClangDiagnosticConfigsWidget::isConfigChooserEmpty() const
void ClangDiagnosticConfigsWidget::setDiagnosticOptions(const QString &options)
{
if (options != m_clangBaseChecks->diagnosticOptionsTextEdit->document()->toPlainText()) {
disconnectDiagnosticOptionsChanged();
if (options != m_clangBaseChecks->diagnosticOptionsTextEdit->document()->toPlainText())
m_clangBaseChecks->diagnosticOptionsTextEdit->document()->setPlainText(options);
connectDiagnosticOptionsChanged();
}
const QString errorMessage
= validateDiagnosticOptions(normalizeDiagnosticInputOptions(options));
@@ -968,20 +949,28 @@ void ClangDiagnosticConfigsWidget::disconnectConfigChooserCurrentIndex()
this, &ClangDiagnosticConfigsWidget::onCurrentConfigChanged);
}
void ClangDiagnosticConfigsWidget::connectDiagnosticOptionsChanged()
void ClangDiagnosticConfigsWidget::connectClangOnlyOptionsChanged()
{
connect(m_clangBaseChecks->useFlagsFromBuildSystemCheckBox,
&QCheckBox::stateChanged,
this,
&ClangDiagnosticConfigsWidget::onClangOnlyOptionsChanged);
connect(m_clangBaseChecks->diagnosticOptionsTextEdit->document(),
&QTextDocument::contentsChanged,
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(),
&QTextDocument::contentsChanged,
this,
&ClangDiagnosticConfigsWidget::onDiagnosticOptionsEdited);
&ClangDiagnosticConfigsWidget::onClangOnlyOptionsChanged);
}
ClangDiagnosticConfigs ClangDiagnosticConfigsWidget::customConfigs() const

View File

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

View File

@@ -99,12 +99,14 @@ CompilerOptionsBuilder::CompilerOptionsBuilder(const ProjectPart &projectPart,
UseSystemHeader useSystemHeader,
UseTweakedHeaderPaths useTweakedHeaderPaths,
UseLanguageDefines useLanguageDefines,
UseBuildSystemWarnings useBuildSystemWarnings,
const QString &clangVersion,
const QString &clangResourceDirectory)
: m_projectPart(projectPart)
, m_useSystemHeader(useSystemHeader)
, m_useTweakedHeaderPaths(useTweakedHeaderPaths)
, m_useLanguageDefines(useLanguageDefines)
, m_useBuildSystemWarnings(useBuildSystemWarnings)
, m_clangVersion(clangVersion)
, m_clangResourceDirectory(clangResourceDirectory)
{
@@ -707,10 +709,11 @@ void CompilerOptionsBuilder::evaluateCompilerFlags()
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.
if (option.startsWith("-w", Qt::CaseInsensitive)
|| option.startsWith("/w", Qt::CaseInsensitive) || option.startsWith("-pedantic")) {
if (m_useBuildSystemWarnings == UseBuildSystemWarnings::No
&& (option.startsWith("-w", Qt::CaseInsensitive)
|| option.startsWith("/w", Qt::CaseInsensitive) || option.startsWith("-pedantic"))) {
// -w, -W, /w, /W...
continue;
}

View File

@@ -36,6 +36,7 @@ enum class UseSystemHeader : char { Yes, No };
enum class UseTweakedHeaderPaths : char { Yes, No };
enum class UseToolchainMacros : 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 clangArgsForCl(const QStringList &args);
@@ -43,10 +44,12 @@ CPPTOOLS_EXPORT QStringList clangArgsForCl(const QStringList &args);
class CPPTOOLS_EXPORT CompilerOptionsBuilder
{
public:
CompilerOptionsBuilder(const ProjectPart &projectPart,
CompilerOptionsBuilder(
const ProjectPart &projectPart,
UseSystemHeader useSystemHeader = UseSystemHeader::No,
UseTweakedHeaderPaths useTweakedHeaderPaths = UseTweakedHeaderPaths::No,
UseLanguageDefines useLanguageDefines = UseLanguageDefines::No,
UseBuildSystemWarnings useBuildSystemWarnings = UseBuildSystemWarnings::No,
const QString &clangVersion = QString(),
const QString &clangResourceDirectory = QString());
@@ -99,6 +102,7 @@ private:
const UseSystemHeader m_useSystemHeader;
const UseTweakedHeaderPaths m_useTweakedHeaderPaths;
const UseLanguageDefines m_useLanguageDefines;
const UseBuildSystemWarnings m_useBuildSystemWarnings;
const QString m_clangVersion;
const QString m_clangResourceDirectory;

View File

@@ -27,6 +27,7 @@
#include "clangdiagnosticconfigsmodel.h"
#include "cpptoolsconstants.h"
#include "cpptoolsreuse.h"
#include <utils/qtcassert.h>
@@ -79,6 +80,24 @@ static QString skipIndexingBigFilesKey()
static QString indexerFileSizeLimitKey()
{ 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)
{
QTC_ASSERT(s->group() == QLatin1String(Constants::CPPTOOLS_SETTINGSGROUP),
@@ -98,7 +117,9 @@ static ClangDiagnosticConfigs customDiagnosticConfigsFromSettings(QSettings *s)
s->value(clangDiagnosticConfigsArrayClangTidyModeKey()).toInt()));
config.setClangTidyChecks(
s->value(clangDiagnosticConfigsArrayClangTidyChecksKey()).toString());
config.setClazyChecks(s->value(clangDiagnosticConfigsArrayClazyChecksKey()).toString());
const QString clazyChecks = s->value(clangDiagnosticConfigsArrayClazyChecksKey()).toString();
config.setClazyChecks(convertToNewClazyChecksFormat(clazyChecks));
configs.append(config);
}
s->endArray();

View File

@@ -27,6 +27,7 @@
#include "cppcodemodelsettings.h"
#include "cpptoolsplugin.h"
#include "cpptools_clazychecks.h"
#include <coreplugin/documentmanager.h>
#include <coreplugin/editormanager/editormanager.h>
@@ -287,4 +288,14 @@ UsePrecompiledHeaders getPchUsage()
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

View File

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

View File

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

View File

@@ -207,7 +207,7 @@ public:
QCheckBox *forceLocalCheckBox;
QLabel *forceLocalLabel;
PathChooser *localExecFileName;
PathChooser *symbolFileName;
PathChooser *localCoreFileName;
QLineEdit *remoteCoreFileName;
QPushButton *selectRemoteCoreButton;
@@ -220,11 +220,11 @@ public:
{
bool isValid() const
{
return validKit && validLocalExecFilename && validCoreFilename;
return validKit && validSymbolFilename && validCoreFilename;
}
bool validKit;
bool validLocalExecFilename;
bool validSymbolFilename;
bool validCoreFilename;
bool localCoreFile;
bool localKit;
@@ -235,7 +235,7 @@ public:
State st;
st.localCoreFile = p.useLocalCoreFile();
st.validKit = (kitChooser->currentKit() != nullptr);
st.validLocalExecFilename = localExecFileName->isValid();
st.validSymbolFilename = symbolFileName->isValid();
if (st.localCoreFile)
st.validCoreFilename = localCoreFileName->isValid();
@@ -274,10 +274,14 @@ AttachCoreDialog::AttachCoreDialog(QWidget *parent)
d->localCoreFileName->setExpectedKind(PathChooser::File);
d->localCoreFileName->setPromptDialogTitle(tr("Select Core File"));
d->localExecFileName = new PathChooser(this);
d->localExecFileName->setHistoryCompleter("LocalExecutable");
d->localExecFileName->setExpectedKind(PathChooser::File);
d->localExecFileName->setPromptDialogTitle(tr("Select Executable"));
d->symbolFileName = new PathChooser(this);
d->symbolFileName->setHistoryCompleter("LocalExecutable");
d->symbolFileName->setExpectedKind(PathChooser::File);
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->setHistoryCompleter("Debugger.StartupScript.History");
@@ -296,7 +300,7 @@ AttachCoreDialog::AttachCoreDialog(QWidget *parent)
formLayout->addRow(tr("Kit:"), d->kitChooser);
formLayout->addRow(d->forceLocalLabel, d->forceLocalCheckBox);
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);
auto line = new QFrame(this);
@@ -321,7 +325,7 @@ int AttachCoreDialog::exec()
{
connect(d->selectRemoteCoreButton, &QAbstractButton::clicked, this, &AttachCoreDialog::selectRemoteCoreFile);
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->forceLocalCheckBox, &QCheckBox::stateChanged, this, &AttachCoreDialog::changed);
connect(d->kitChooser, &KitChooser::currentIndexChanged, this, &AttachCoreDialog::changed);
@@ -337,8 +341,8 @@ int AttachCoreDialog::exec()
d->localCoreFileName->setFocus();
else
d->remoteCoreFileName->setFocus();
} else if (!st.validLocalExecFilename) {
d->localExecFileName->setFocus();
} else if (!st.validSymbolFilename) {
d->symbolFileName->setFocus();
}
return QDialog::exec();
@@ -366,9 +370,9 @@ void AttachCoreDialog::coreFileChanged(const QString &core)
Runnable debugger = DebuggerKitInformation::runnable(k);
CoreInfo cinfo = CoreInfo::readExecutableNameFromCore(debugger, core);
if (!cinfo.foundExecutableName.isEmpty())
d->localExecFileName->setFileName(FileName::fromString(cinfo.foundExecutableName));
else if (!d->localExecFileName->isValid() && !cinfo.rawStringFromCore.isEmpty())
d->localExecFileName->setFileName(FileName::fromString(cinfo.rawStringFromCore));
d->symbolFileName->setFileName(FileName::fromString(cinfo.foundExecutableName));
else if (!d->symbolFileName->isValid() && !cinfo.rawStringFromCore.isEmpty())
d->symbolFileName->setFileName(FileName::fromString(cinfo.rawStringFromCore));
}
changed();
}
@@ -411,14 +415,14 @@ QString AttachCoreDialog::localCoreFile() const
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)

View File

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

View File

@@ -39,11 +39,13 @@
#include <texteditor/semantichighlighter.h>
#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
#include <texteditor/textmark.h>
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h>
#include <utils/utilsicons.h>
#include <QDebug>
#include <QLoggingCategory>
@@ -62,6 +64,25 @@ namespace LanguageClient {
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)
: m_id(Core::Id::fromString(QUuid::createUuid().toString()))
, m_completionProvider(this)
@@ -88,6 +109,8 @@ Client::~Client()
widget->setRefactorMarkers(RefactorMarker::filterOutType(widget->refactorMarkers(), id()));
}
}
for (const DocumentUri &uri : m_diagnostics.keys())
removeDiagnostics(uri);
}
void Client::initialize()
@@ -155,10 +178,12 @@ void Client::openDocument(Core::IDocument *document)
return;
}
}
auto uri = DocumentUri::fromFileName(filePath);
showDiagnostics(uri);
auto textDocument = qobject_cast<TextDocument *>(document);
TextDocumentItem item;
item.setLanguageId(TextDocumentItem::mimeTypeToLanguageId(document->mimeType()));
item.setUri(DocumentUri::fromFileName(filePath));
item.setUri(uri);
item.setText(QString::fromUtf8(document->contents()));
item.setVersion(textDocument ? textDocument->document()->revision() : 0);
@@ -673,6 +698,8 @@ bool Client::reset()
m_openedDocument.clear();
m_serverCapabilities = ServerCapabilities();
m_dynamicCapabilities.reset();
for (const DocumentUri &uri : m_diagnostics.keys())
removeDiagnostics(uri);
return true;
}
@@ -749,6 +776,25 @@ void Client::showMessageBox(const ShowMessageRequestParams &message, const Messa
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)
{
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());
paramsValid = params.isValid(&error);
if (paramsValid)
LanguageClientManager::publishDiagnostics(m_id, params, this);
handleDiagnostics(params);
} else if (method == LogMessageNotification::methodName) {
auto params = dynamic_cast<const LogMessageNotification *>(content)->params().value_or(LogMessageParams());
paramsValid = params.isValid(&error);
@@ -823,6 +869,21 @@ void Client::handleMethod(const QString &method, MessageId id, const IContent *c
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)
{
QTC_ASSERT(m_state == InitializeRequested, return);

View File

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

View File

@@ -49,30 +49,6 @@ namespace LanguageClient {
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()
{
JsonRpcMessageHandler::registerMessageProvider<PublishDiagnosticsNotification>();
@@ -107,68 +83,6 @@ void LanguageClientManager::init()
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)
{
QTC_ASSERT(client, return);
@@ -210,7 +124,6 @@ void LanguageClientManager::deleteClient(Client *client)
{
QTC_ASSERT(client, return);
client->disconnect();
managerInstance->removeMarks(client->id());
managerInstance->m_clients.removeAll(client);
client->deleteLater();
}
@@ -269,7 +182,6 @@ void LanguageClientManager::clientFinished(Client *client)
const bool unexpectedFinish = client->state() != Client::Shutdown
&& client->state() != Client::ShutdownRequested;
if (unexpectedFinish && !m_shuttingDown && client->reset()) {
removeMarks(client->id());
client->disconnect(this);
client->log(tr("Unexpectedly finished. Restarting in %1 seconds.").arg(restartTimeoutS),
Core::MessageManager::Flash);
@@ -312,7 +224,6 @@ void LanguageClientManager::editorsClosed(const QList<Core::IEditor *> &editors)
{
for (auto iEditor : editors) {
if (auto editor = qobject_cast<TextEditor::BaseTextEditor *>(iEditor)) {
removeMarks(editor->document()->filePath());
const DidCloseTextDocumentParams params(TextDocumentIdentifier(
DocumentUri::fromFileName(editor->document()->filePath())));
for (Client *interface : reachableClients())

View File

@@ -55,14 +55,6 @@ public:
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 QVector<Client *> clients();
@@ -101,7 +93,6 @@ private:
bool m_shuttingDown = false;
QVector<Client *> m_clients;
QHash<Utils::FileName, QHash<Core::Id, QVector<LanguageClientMark *>>> m_marks;
QHash<LanguageServerProtocol::MessageId, QList<Client *>> m_exclusiveRequests;
friend class LanguageClientPlugin;

View File

@@ -36,10 +36,14 @@
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h>
#include <cpptools/cpptoolsconstants.h>
#include <projectexplorer/editorconfiguration.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <qtsupport/profilereader.h>
#include <texteditor/icodestylepreferences.h>
#include <texteditor/tabsettings.h>
#include <texteditor/texteditorsettings.h>
#include <utils/algorithm.h>
#include <utils/filesystemwatcher.h>
@@ -378,6 +382,19 @@ void QmakePriFile::watchFolders(const QSet<FileName> &folders)
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
{
return m_recursiveEnumerateFiles.contains(filePath);
@@ -747,7 +764,8 @@ bool QmakePriFile::renameFile(const QString &oldName,
ProWriter::addFiles(includeFile, &lines,
QStringList(newName),
varNameForAdding(mimeType));
varNameForAdding(mimeType),
continuationIndent());
if (mode == Change::Save)
save(lines);
includeFile->deref();
@@ -777,7 +795,8 @@ void QmakePriFile::changeFiles(const QString &mimeType,
if (change == AddToProFile) {
// Use the first variable for adding.
ProWriter::addFiles(includeFile, &lines, filePaths, varNameForAdding(mimeType));
ProWriter::addFiles(includeFile, &lines, filePaths, varNameForAdding(mimeType),
continuationIndent());
notChanged->clear();
} else { // RemoveFromProFile
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::PutFlags(flags),
scope);
scope, continuationIndent());
save(lines);
includeFile->deref();

View File

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

View File

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

View File

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

View File

@@ -27,7 +27,11 @@ Project {
Depends { name: "QtSupport" }
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.includePaths: base.concat([
".",
@@ -51,6 +55,7 @@ Project {
"components/texteditor",
"qmldesignerextension",
"qmldesignerextension/connectioneditor",
"qmldesignerextension/timelineeditor",
])
Properties {
@@ -635,6 +640,72 @@ Project {
"texttool/textedititemwidget.h",
"texttool/texttool.cpp",
"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);
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 transformBlockSelection(TransformationMethod method);
@@ -836,6 +839,68 @@ TextEditorWidgetPrivate::~TextEditorWidgetPrivate()
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
/*!
@@ -3490,6 +3555,13 @@ QPoint TextEditorWidget::toolTipPosition(const QTextCursor &c) const
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)
{
const QPoint toolTipPoint = q->toolTipPosition(c);
@@ -3516,33 +3588,7 @@ bool TextEditorWidgetPrivate::processAnnotaionTooltipRequest(const QTextBlock &b
for (const AnnotationRect &annotationRect : m_annotationRects[block.blockNumber()]) {
if (!annotationRect.rect.contains(pos))
continue;
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);
showTextMarksToolTip(q->mapToGlobal(pos), blockUserData->marks(), annotationRect.mark);
return true;
}
return false;
@@ -5787,16 +5833,10 @@ void TextEditorWidget::extraAreaMouseEvent(QMouseEvent *e)
int line = cursor.blockNumber() + 1;
if (d->extraAreaPreviousMarkTooltipRequestedLine != line) {
if (auto data = static_cast<TextBlockUserData *>(cursor.block().userData())) {
if (data->marks().isEmpty()) {
if (data->marks().isEmpty())
ToolTip::hide();
} else {
auto layout = new QGridLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(2);
foreach (TextMark *mark, data->marks())
mark->addToToolTipLayout(layout);
ToolTip::show(mapToGlobal(e->pos()), layout, this);
}
else
d->showTextMarksToolTip(mapToGlobal(e->pos()), data->marks());
}
}
d->extraAreaPreviousMarkTooltipRequestedLine = line;

View File

@@ -59,6 +59,7 @@ class HighlightScrollBarController;
namespace TextEditor {
class TextDocument;
class TextMark;
class BaseHoverHandler;
class RefactorOverlay;
struct RefactorMarker;
@@ -68,6 +69,7 @@ class IAssistProvider;
class ICodeStylePreferences;
class CompletionAssistProvider;
using RefactorMarkers = QList<RefactorMarker>;
using TextMarks = QList<TextMark *>;
namespace Internal {
class BaseTextEditorPrivate;
@@ -274,6 +276,9 @@ public:
QRegion translatedLineRegion(int lineStart, int lineEnd) 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);

View File

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

View File

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

View File

@@ -51,11 +51,12 @@ public:
static void putVarValues(ProFile *profile, QStringList *lines,
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,
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,
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,
"",
"SOURCES += \\\n"
" foo"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
@@ -111,7 +111,7 @@ void tst_ProFileWriter::adds_data()
"# test file\n"
"\n"
"SOURCES += \\\n"
" foo"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
@@ -120,7 +120,7 @@ void tst_ProFileWriter::adds_data()
"\n"
"\n",
"SOURCES += \\\n"
" foo\n"
"\tfoo\n"
"\n"
"\n"
"\n"
@@ -135,7 +135,7 @@ void tst_ProFileWriter::adds_data()
"# test file\n"
"\n"
"SOURCES += \\\n"
" foo\n"
"\tfoo\n"
"\n"
"\n"
"\n"
@@ -147,7 +147,7 @@ void tst_ProFileWriter::adds_data()
"# test file\n"
"\n"
"SOURCES = \\\n"
" foo"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::OneLine,
@@ -184,43 +184,43 @@ void tst_ProFileWriter::adds_data()
"unix:SOURCES = some files\n"
"\n"
"SOURCES += \\\n"
" foo"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
"add new after some scope", f_foo, 0,
"unix {\n"
" SOMEVAR = foo\n"
"\tSOMEVAR = foo\n"
"}",
"unix {\n"
" SOMEVAR = foo\n"
"\tSOMEVAR = foo\n"
"}\n"
"\n"
"SOURCES += \\\n"
" foo"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
"add to existing (wrong operator)", f_foo, 0,
"SOURCES = some files",
"SOURCES = some files \\\n"
" foo"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
"insert at end", f_foo_bar, 0,
"SOURCES = some files",
"SOURCES = some files \\\n"
" bar \\\n"
" foo"
"\tbar \\\n"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
"insert into empty", f_foo_bar, 0,
"SOURCES =",
"SOURCES = \\\n"
" bar \\\n"
" foo"
"\tbar \\\n"
"\tfoo"
},
{
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,
"SOURCES = some files # comment",
"SOURCES = some files \\ # comment\n"
" foo"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
"add to existing after comment line (wrong operator)", f_foo, 0,
"SOURCES = some \\\n"
" # comment\n"
" files",
"\tfiles",
"SOURCES = some \\\n"
" # comment\n"
" files \\\n"
" foo"
"\tfiles \\\n"
"\tfoo"
},
{
PW::AppendValues|PW::AssignOperator|PW::MultiLine,
"add to existing", f_foo, 0,
"SOURCES = some files",
"SOURCES = some files \\\n"
" foo"
"\tfoo"
},
{
PW::ReplaceValues|PW::AssignOperator|PW::MultiLine,
"replace existing multi", f_foo_bar, 0,
"SOURCES = some files",
"SOURCES = \\\n"
" foo \\\n"
" bar"
"\tfoo \\\n"
"\tbar"
},
{
PW::ReplaceValues|PW::AssignOperator|PW::OneLine,
@@ -278,7 +278,7 @@ void tst_ProFileWriter::adds_data()
"replace existing complex last", f_foo_bar, 0,
"SOURCES = some \\\n"
" # comment\n"
" files",
"\tfiles",
"SOURCES = foo bar"
},
{
@@ -286,7 +286,7 @@ void tst_ProFileWriter::adds_data()
"replace existing complex middle 1", f_foo_bar, 0,
"SOURCES = some \\\n"
" # comment\n"
" files\n"
"\tfiles\n"
"HEADERS = blubb",
"SOURCES = foo bar\n"
"HEADERS = blubb"
@@ -296,7 +296,7 @@ void tst_ProFileWriter::adds_data()
"replace existing complex middle 2", f_foo_bar, 0,
"SOURCES = some \\\n"
" # comment\n"
" files\n"
"\tfiles\n"
"\n"
"HEADERS = blubb",
"SOURCES = foo bar\n"
@@ -308,7 +308,7 @@ void tst_ProFileWriter::adds_data()
"replace existing complex middle 3", f_foo_bar, 0,
"SOURCES = some \\\n"
" # comment\n"
" files \\\n"
"\tfiles \\\n"
"\n"
"HEADERS = blubb",
"SOURCES = foo bar\n"
@@ -324,7 +324,7 @@ void tst_ProFileWriter::adds_data()
"SOURCES = yo\n"
"\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",
"# test file\n"
"dog {\n"
" HEADERS += yo\n"
"\tHEADERS += yo\n"
"}",
"# test file\n"
"dog {\n"
" HEADERS += yo\n"
"\tHEADERS += yo\n"
"\n"
" SOURCES += foo\n"
"\tSOURCES += foo\n"
"}"
},
{
@@ -356,7 +356,7 @@ void tst_ProFileWriter::adds_data()
" yo \\\n"
" blubb\n"
"\n"
" SOURCES += foo\n"
"\tSOURCES += foo\n"
"}"
},
{
@@ -367,7 +367,7 @@ void tst_ProFileWriter::adds_data()
"}",
"# test file\n"
"dog {\n"
" SOURCES += foo\n"
"\tSOURCES += foo\n"
"}"
},
{
@@ -377,9 +377,9 @@ void tst_ProFileWriter::adds_data()
"dog:HEADERS += yo",
"# test file\n"
"dog {\n"
" HEADERS += yo\n"
"\tHEADERS += yo\n"
"\n"
" SOURCES += foo\n"
"\tSOURCES += foo\n"
"}"
},
{
@@ -392,10 +392,10 @@ void tst_ProFileWriter::adds_data()
"blubb()",
"# test file\n"
"dog {\n"
" HEADERS += yo \\\n"
"\tHEADERS += yo \\\n"
" you\n"
"\n"
" SOURCES += foo\n"
"\tSOURCES += foo\n"
"}\n"
"\n"
"blubb()"
@@ -413,8 +413,8 @@ void tst_ProFileWriter::adds_data()
" SOMEVAR = foo\n"
" }\n"
"\n"
" SOURCES += \\\n"
" foo\n"
"\tSOURCES += \\\n"
"\t\tfoo\n"
"}"
},
{
@@ -425,7 +425,7 @@ void tst_ProFileWriter::adds_data()
"}",
"# test file\n"
"dog: {\n"
" SOURCES += foo\n"
"\tSOURCES += foo\n"
"}"
},
{
@@ -435,7 +435,7 @@ void tst_ProFileWriter::adds_data()
"dog:SOURCES = yo",
"# test file\n"
"dog:SOURCES = yo \\\n"
" foo"
"\t\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
@@ -446,8 +446,8 @@ void tst_ProFileWriter::adds_data()
"animal:!dog:SOURCES = yo\n"
"\n"
"dog {\n"
" SOURCES += \\\n"
" foo\n"
"\tSOURCES += \\\n"
"\t\tfoo\n"
"}"
},
};
@@ -478,7 +478,7 @@ void tst_ProFileWriter::adds()
QMakeParser parser(0, &vfs, &parseHandler);
ProFile *proFile = parser.parsedProBlock(QStringRef(&input), 0, QLatin1String(BASE_DIR "/test.pro"), 1);
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();
QCOMPARE(lines.join(QLatin1Char('\n')), output);
@@ -692,7 +692,7 @@ void tst_ProFileWriter::addFiles()
QStringList lines = input.split(QLatin1Char('\n'));
QString output = QLatin1String(
"SOURCES = foo.cpp \\\n"
" sub/bar.cpp"
"\tsub/bar.cpp"
);
QMakeVfs vfs;
@@ -701,7 +701,7 @@ void tst_ProFileWriter::addFiles()
QVERIFY(proFile);
QmakeProjectManager::Internal::ProWriter::addFiles(proFile, &lines,
QStringList() << QString::fromLatin1(BASE_DIR "/sub/bar.cpp"),
QLatin1String("SOURCES"));
QLatin1String("SOURCES"), "\t");
proFile->deref();
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()));
}
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)
{
ProjectPart part = projectPart;
@@ -171,6 +187,7 @@ TEST_F(CompilerOptionsBuilder, HeaderPathOptionsOrder)
CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version",
""};
@@ -196,6 +213,7 @@ TEST_F(CompilerOptionsBuilder, HeaderPathOptionsOrderCl)
CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version",
""};
compilerOptionsBuilder.evaluateCompilerFlags();
@@ -221,6 +239,7 @@ TEST_F(CompilerOptionsBuilder, UseSystemHeader)
CppTools::UseSystemHeader::Yes,
CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version",
""};
@@ -265,6 +284,7 @@ TEST_F(CompilerOptionsBuilder, ClangHeadersAndCppIncludesPathsOrderMacOs)
CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version",
"");
@@ -310,6 +330,7 @@ TEST_F(CompilerOptionsBuilder, ClangHeadersAndCppIncludesPathsOrderLinux)
CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version",
"");
@@ -356,6 +377,7 @@ TEST_F(CompilerOptionsBuilder, ClangHeadersAndCppIncludesPathsOrderNoVersion)
CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version",
"");
@@ -403,6 +425,7 @@ TEST_F(CompilerOptionsBuilder, ClangHeadersAndCppIncludesPathsOrderAndroidClang)
CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version",
"");
@@ -480,6 +503,7 @@ TEST_F(CompilerOptionsBuilder, InsertWrappedQtHeaders)
CppTools::UseSystemHeader::Yes,
CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version",
""};
@@ -613,6 +637,7 @@ TEST_F(CompilerOptionsBuilder, BuildAllOptions)
CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version",
"");
@@ -652,6 +677,7 @@ TEST_F(CompilerOptionsBuilder, BuildAllOptionsCl)
CppTools::UseSystemHeader::No,
CppTools::UseTweakedHeaderPaths::Yes,
CppTools::UseLanguageDefines::No,
CppTools::UseBuildSystemWarnings::No,
"dummy_version",
"");