From 2a06ec7da3cb48299c392a798ed765c831c5fa07 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 14 Jul 2017 15:22:11 +0200 Subject: [PATCH 01/37] Welcome: Add links to the new video tutorials from Tutorials tab Change-Id: If38ff8abd3ddedae7cd368bc67d533dfeff22208 Reviewed-by: Leena Miettinen Reviewed-by: Alessandro Portale Reviewed-by: Eike Ziller --- .../images/icons/videotutorialicon.png | Bin 0 -> 3511 bytes src/plugins/qtsupport/qtcreator_tutorials.xml | 46 +++++++++++------- src/plugins/qtsupport/qtsupport.qrc | 1 + 3 files changed, 30 insertions(+), 17 deletions(-) create mode 100644 src/plugins/qtsupport/images/icons/videotutorialicon.png diff --git a/src/plugins/qtsupport/images/icons/videotutorialicon.png b/src/plugins/qtsupport/images/icons/videotutorialicon.png new file mode 100644 index 0000000000000000000000000000000000000000..71b5a91cf27048982f7ab0463d5a7f8c5db3c5b8 GIT binary patch literal 3511 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 hWaLriBr#C qt quick,qml,c++ + + + + qt creator,qt quick,automotive,safe renderer,controls + + + + qt creator,embedded,device creation + + + + + qt creator,qt quick,embedded + + + + + qt creator,widgets + + + + qt creator,qt quick + + + + qt creator,SCXML + qt creator @@ -47,7 +74,7 @@ - qt creator,cpu usage analyzer,perf + qt creator,cpu usage analyzer,perf,embedded,device creation @@ -77,14 +104,7 @@ windows - - - qt creator,SCXML - - - - qt,embedded,device creation - + qt quick designer,controls @@ -97,10 +117,6 @@ qt creator,android - - - qml,qml profiler - macos @@ -113,10 +129,6 @@ qt webengine - - - automotive - qt,qt quick,screen resolution diff --git a/src/plugins/qtsupport/qtsupport.qrc b/src/plugins/qtsupport/qtsupport.qrc index ff9d929b614..50d90e55d85 100644 --- a/src/plugins/qtsupport/qtsupport.qrc +++ b/src/plugins/qtsupport/qtsupport.qrc @@ -15,5 +15,6 @@ images/icons/tutorialicon.png images/icons/worldsummit15.png images/icons/worldsummit16.png + images/icons/videotutorialicon.png From 698e323a73b48ec0aa16babd9d5fa02e664c5a71 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 19 Jul 2017 14:51:21 +0200 Subject: [PATCH 02/37] TextEditor: Make annotation position configurable Change-Id: Ib59c9770390523e1863ac507ce43512ba679c591 Reviewed-by: Eike Ziller Reviewed-by: Alessandro Portale --- src/plugins/texteditor/displaysettings.cpp | 9 + src/plugins/texteditor/displaysettings.h | 13 ++ .../texteditor/displaysettingspage.cpp | 11 ++ src/plugins/texteditor/displaysettingspage.ui | 156 +++++++++++------- src/plugins/texteditor/texteditor.cpp | 84 ++++++++-- src/plugins/texteditor/textmark.cpp | 65 +++++--- src/plugins/texteditor/textmark.h | 8 +- 7 files changed, 241 insertions(+), 105 deletions(-) diff --git a/src/plugins/texteditor/displaysettings.cpp b/src/plugins/texteditor/displaysettings.cpp index 196b9434c2f..3d2eb5c084f 100644 --- a/src/plugins/texteditor/displaysettings.cpp +++ b/src/plugins/texteditor/displaysettings.cpp @@ -45,6 +45,8 @@ static const char scrollBarHighlightsKey[] = "ScrollBarHighlights"; static const char animateNavigationWithinFileKey[] = "AnimateNavigationWithinFile"; static const char animateWithinFileTimeMaxKey[] = "AnimateWithinFileTimeMax"; static const char displayAnnotationsKey[] = "DisplayAnnotations"; +static const char annotationAlignmentKey[] = "AnnotationAlignment"; +static const char minimalAnnotationContentKey[] = "MinimalAnnotationContent"; static const char groupPostfix[] = "DisplaySettings"; namespace TextEditor { @@ -71,6 +73,7 @@ void DisplaySettings::toSettings(const QString &category, QSettings *s) const s->setValue(QLatin1String(scrollBarHighlightsKey), m_scrollBarHighlights); s->setValue(QLatin1String(animateNavigationWithinFileKey), m_animateNavigationWithinFile); s->setValue(QLatin1String(displayAnnotationsKey), m_displayAnnotations); + s->setValue(QLatin1String(annotationAlignmentKey), static_cast(m_annotationAlignment)); s->endGroup(); } @@ -100,6 +103,10 @@ void DisplaySettings::fromSettings(const QString &category, const QSettings *s) m_animateNavigationWithinFile = s->value(group + QLatin1String(animateNavigationWithinFileKey), m_animateNavigationWithinFile).toBool(); m_animateWithinFileTimeMax = s->value(group + QLatin1String(animateWithinFileTimeMaxKey), m_animateWithinFileTimeMax).toInt(); m_displayAnnotations = s->value(group + QLatin1String(displayAnnotationsKey), m_displayAnnotations).toBool(); + m_annotationAlignment = static_cast( + s->value(group + QLatin1String(annotationAlignmentKey), + static_cast(m_annotationAlignment)).toInt()); + m_minimalAnnotationContent = s->value(group + QLatin1String(minimalAnnotationContentKey), m_minimalAnnotationContent).toInt(); } bool DisplaySettings::equals(const DisplaySettings &ds) const @@ -122,6 +129,8 @@ bool DisplaySettings::equals(const DisplaySettings &ds) const && m_animateNavigationWithinFile == ds.m_animateNavigationWithinFile && m_animateWithinFileTimeMax == ds.m_animateWithinFileTimeMax && m_displayAnnotations == ds.m_displayAnnotations + && m_annotationAlignment == ds.m_annotationAlignment + && m_minimalAnnotationContent == ds.m_minimalAnnotationContent ; } diff --git a/src/plugins/texteditor/displaysettings.h b/src/plugins/texteditor/displaysettings.h index a37343bb486..326f9aad069 100644 --- a/src/plugins/texteditor/displaysettings.h +++ b/src/plugins/texteditor/displaysettings.h @@ -27,12 +27,21 @@ #include "texteditor_global.h" +#include "QMetaType" + QT_BEGIN_NAMESPACE class QSettings; QT_END_NAMESPACE namespace TextEditor { +enum class AnnotationAlignment +{ + NextToContent, + NextToMargin, + RightSide +}; + class TEXTEDITOR_EXPORT DisplaySettings { public: @@ -59,6 +68,8 @@ public: bool m_animateNavigationWithinFile = false; int m_animateWithinFileTimeMax = 333; // read only setting bool m_displayAnnotations = true; + AnnotationAlignment m_annotationAlignment = AnnotationAlignment::RightSide; + int m_minimalAnnotationContent = 15; bool equals(const DisplaySettings &ds) const; }; @@ -67,3 +78,5 @@ inline bool operator==(const DisplaySettings &t1, const DisplaySettings &t2) { r inline bool operator!=(const DisplaySettings &t1, const DisplaySettings &t2) { return !t1.equals(t2); } } // namespace TextEditor + +Q_DECLARE_METATYPE(TextEditor::AnnotationAlignment) diff --git a/src/plugins/texteditor/displaysettingspage.cpp b/src/plugins/texteditor/displaysettingspage.cpp index 7ae27e11d73..2289ba2135a 100644 --- a/src/plugins/texteditor/displaysettingspage.cpp +++ b/src/plugins/texteditor/displaysettingspage.cpp @@ -120,6 +120,12 @@ void DisplaySettingsPage::settingsFromUI(DisplaySettings &displaySettings, displaySettings.m_scrollBarHighlights = d->m_page->scrollBarHighlights->isChecked(); displaySettings.m_animateNavigationWithinFile = d->m_page->animateNavigationWithinFile->isChecked(); displaySettings.m_displayAnnotations = d->m_page->displayAnnotations->isChecked(); + if (d->m_page->leftAligned->isChecked()) + displaySettings.m_annotationAlignment = AnnotationAlignment::NextToContent; + else if (d->m_page->atMargin->isChecked()) + displaySettings.m_annotationAlignment = AnnotationAlignment::NextToMargin; + else if (d->m_page->rightAligned->isChecked()) + displaySettings.m_annotationAlignment = AnnotationAlignment::RightSide; } void DisplaySettingsPage::settingsToUI() @@ -144,6 +150,11 @@ void DisplaySettingsPage::settingsToUI() d->m_page->scrollBarHighlights->setChecked(displaySettings.m_scrollBarHighlights); d->m_page->animateNavigationWithinFile->setChecked(displaySettings.m_animateNavigationWithinFile); d->m_page->displayAnnotations->setChecked(displaySettings.m_displayAnnotations); + switch (displaySettings.m_annotationAlignment) { + case AnnotationAlignment::NextToContent: d->m_page->leftAligned->setChecked(true); break; + case AnnotationAlignment::NextToMargin: d->m_page->atMargin->setChecked(true); break; + case AnnotationAlignment::RightSide: d->m_page->rightAligned->setChecked(true); break; + } } const DisplaySettings &DisplaySettingsPage::displaySettings() const diff --git a/src/plugins/texteditor/displaysettingspage.ui b/src/plugins/texteditor/displaysettingspage.ui index 1663840272e..aa8dd2cd446 100644 --- a/src/plugins/texteditor/displaysettingspage.ui +++ b/src/plugins/texteditor/displaysettingspage.ui @@ -6,11 +6,24 @@ 0 0 - 501 - 339 + 452 + 458 + + + + Qt::Vertical + + + + 20 + 8 + + + + @@ -61,57 +74,16 @@ - - - - Qt::Vertical - - - - 20 - 8 - - - - Display - - + + - &Highlight matching parentheses - - - - - - - Highlight &blocks - - - - - - - Highlight current &line - - - - - - - Display line &numbers - - - - - - - Auto-fold first &comment + Display file encoding @@ -122,20 +94,6 @@ - - - - Always open links in another split - - - - - - - Display file encoding - - - @@ -143,6 +101,27 @@ + + + + Display line &numbers + + + + + + + &Highlight matching parentheses + + + + + + + Always open links in another split + + + @@ -153,6 +132,27 @@ + + + + Highlight current &line + + + + + + + Auto-fold first &comment + + + + + + + Highlight &blocks + + + @@ -181,10 +181,39 @@ - - + + + + + + + Annotations next to lines + + + true + + + + - Display annotations behind lines + Next to editor content + + + + + + + Next to right margin + + + + + + + Aligned at right side + + + true @@ -204,7 +233,6 @@ centerOnScroll autoFoldFirstComment scrollBarHighlights - displayAnnotations highlightCurrentLine highlightBlocks animateMatchingParentheses diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index aa917a22221..692faa1c509 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -393,7 +393,7 @@ public: bool expanded, bool active, bool hovered) const; - void drawLineAnnotation(QPainter &painter, const QTextBlock &block); + void drawLineAnnotation(QPainter &painter, const QTextBlock &block, qreal start); void toggleBlockVisible(const QTextBlock &block); QRect foldBox(); @@ -484,6 +484,7 @@ public: Id m_tabSettingsId; ICodeStylePreferences *m_codeStylePreferences = nullptr; DisplaySettings m_displaySettings; + bool m_annotationsrRight = true; MarginSettings m_marginSettings; // apply when making visible the first time, for the split case bool m_fontSettingsNeedsApply = true; @@ -506,6 +507,7 @@ public: const TextMark *mark; }; QMap> m_annotationRects; + QRectF getLastLineLineRect(const QTextBlock &block); RefactorOverlay *m_refactorOverlay = nullptr; QString m_contextHelpId; @@ -3788,7 +3790,41 @@ static QTextLayout::FormatRange createBlockCursorCharFormatRange(int pos, const return o; } -void TextEditorWidgetPrivate::drawLineAnnotation(QPainter &painter, const QTextBlock &block) +static TextMarks availableMarks(const TextMarks &marks, + QRectF &boundingRect, + const QFontMetrics &fm, + const qreal itemOffset) +{ + TextMarks ret; + bool first = true; + for (TextMark *mark : marks) { + const TextMark::AnnotationRects &rects = mark->annotationRects( + boundingRect, fm, first ? 0 : itemOffset, 0); + if (rects.annotationRect.isEmpty()) + break; + boundingRect.setLeft(rects.fadeOutRect.right()); + ret.append(mark); + if (boundingRect.isEmpty()) + break; + first = false; + } + return ret; +} + +QRectF TextEditorWidgetPrivate::getLastLineLineRect(const QTextBlock &block) +{ + const QTextLayout *layout = block.layout(); + const int lineCount = layout->lineCount(); + if (lineCount < 1) + return QRectF(); + const QTextLine line = layout->lineAt(lineCount - 1); + const QPointF contentOffset = q->contentOffset(); + const qreal top = q->blockBoundingGeometry(block).translated(contentOffset).top(); + return line.naturalTextRect().translated(contentOffset.x(), top).adjusted(0, 0, -1, -1); +} + +void TextEditorWidgetPrivate::drawLineAnnotation( + QPainter &painter, const QTextBlock &block, qreal rightMargin) { if (!m_displaySettings.m_displayAnnotations) return; @@ -3801,30 +3837,44 @@ void TextEditorWidgetPrivate::drawLineAnnotation(QPainter &painter, const QTextB if (marks.isEmpty()) return; - const QTextLayout *layout = block.layout(); - const int lineCount = layout->lineCount(); - if (lineCount < 1) + const QRectF lineRect = getLastLineLineRect(block); + if (lineRect.isNull()) return; - const QTextLine line = layout->lineAt(lineCount - 1); - const QPointF contentOffset = q->contentOffset(); - const qreal top = q->blockBoundingGeometry(block).translated(contentOffset).top(); - const QRectF lineRect = - line.naturalTextRect().translated(contentOffset.x(), top).adjusted(0, 0, -1, -1); Utils::sort(marks, [](const TextMark* mark1, const TextMark* mark2){ return mark1->priority() > mark2->priority(); }); const qreal itemOffset = q->fontMetrics().lineSpacing(); - qreal x = lineRect.right() + itemOffset * 2; + const qreal initialOffset = itemOffset * 2; + const qreal minimalContentWidth = q->fontMetrics().width('X') + * m_displaySettings.m_minimalAnnotationContent; + QRectF boundingRect(lineRect.topLeft().x(), lineRect.topLeft().y(), + q->viewport()->width() - lineRect.right(), lineRect.height()); + qreal offset = initialOffset; + if (marks.isEmpty()) + return; + if (m_displaySettings.m_annotationAlignment == AnnotationAlignment::NextToMargin + && rightMargin > lineRect.right() + offset + && q->viewport()->width() > rightMargin + minimalContentWidth) { + offset = rightMargin - lineRect.right(); + } else if (m_displaySettings.m_annotationAlignment != AnnotationAlignment::NextToContent) { + marks = availableMarks(marks, boundingRect, q->fontMetrics(), itemOffset); + if (boundingRect.width() > 0) + offset = qMax(boundingRect.width(), initialOffset); + } + qreal x = lineRect.right(); for (const TextMark *mark : marks) { - QRectF annotationRect(x, lineRect.top(), q->viewport()->width() - x, lineRect.height()); - if (annotationRect.width() <= 0) + boundingRect = QRectF(x, lineRect.top(), q->viewport()->width() - x, lineRect.height()); + if (boundingRect.isEmpty()) break; - mark->paintAnnotation(&painter, &annotationRect); - x += annotationRect.width() + itemOffset; - m_annotationRects[block.blockNumber()].append({annotationRect, mark}); + + // paint annotation + mark->paintAnnotation(painter, &boundingRect, offset, itemOffset / 2); + x = boundingRect.right(); + offset = itemOffset / 2; + m_annotationRects[block.blockNumber()].append({boundingRect, mark}); } } @@ -4469,7 +4519,7 @@ void TextEditorWidget::paintEvent(QPaintEvent *e) painter.restore(); } } - d->drawLineAnnotation(painter, block); + d->drawLineAnnotation(painter, block, lineX < viewportRect.width() ? lineX : 0); block = nextVisibleBlock; top = bottom; diff --git a/src/plugins/texteditor/textmark.cpp b/src/plugins/texteditor/textmark.cpp index 76050e1902e..1e3c7bd4b50 100644 --- a/src/plugins/texteditor/textmark.cpp +++ b/src/plugins/texteditor/textmark.cpp @@ -121,43 +121,58 @@ void TextMark::paintIcon(QPainter *painter, const QRect &rect) const m_icon.paint(painter, rect, Qt::AlignCenter); } -void TextMark::paintAnnotation(QPainter *painter, QRectF *annotationRect) const +void TextMark::paintAnnotation(QPainter &painter, QRectF *annotationRect, + const qreal fadeInOffset, const qreal fadeOutOffset) const { QString text = lineAnnotation(); if (text.isEmpty()) return; - const AnnotationRects &rects = annotationRects(*annotationRect, painter->fontMetrics()); + const AnnotationRects &rects = annotationRects(*annotationRect, painter.fontMetrics(), + fadeInOffset, fadeOutOffset); + const QColor &markColor = m_hasColor ? Utils::creatorTheme()->color(m_color).toHsl() + : painter.pen().color(); + const AnnotationColors &colors = AnnotationColors::getAnnotationColors( + markColor, painter.background().color()); - const QColor markColor = m_hasColor ? Utils::creatorTheme()->color(m_color).toHsl() - : painter->pen().color(); - const AnnotationColors &colors = - AnnotationColors::getAnnotationColors(markColor, painter->background().color()); - - painter->save(); - painter->setPen(colors.rectColor); - painter->setBrush(colors.rectColor); - painter->drawRect(rects.annotationRect); - painter->setPen(colors.textColor); - paintIcon(painter, rects.iconRect.toAlignedRect()); - painter->drawText(rects.textRect, Qt::AlignLeft, rects.text); - painter->restore(); - *annotationRect = rects.annotationRect; + painter.save(); + QLinearGradient grad(rects.fadeInRect.topLeft(), rects.fadeInRect.topRight()); + grad.setColorAt(0.0, Qt::transparent); + grad.setColorAt(1.0, colors.rectColor); + painter.fillRect(rects.fadeInRect, grad); + painter.fillRect(rects.annotationRect, colors.rectColor); + painter.setPen(colors.textColor); + paintIcon(&painter, rects.iconRect.toAlignedRect()); + painter.drawText(rects.textRect, Qt::AlignLeft, rects.text); + if (rects.fadeOutRect.isValid()) { + grad = QLinearGradient(rects.fadeOutRect.topLeft(), rects.fadeOutRect.topRight()); + grad.setColorAt(0.0, colors.rectColor); + grad.setColorAt(1.0, Qt::transparent); + painter.fillRect(rects.fadeOutRect, grad); + } + painter.restore(); + annotationRect->setRight(rects.fadeOutRect.right()); } TextMark::AnnotationRects TextMark::annotationRects(const QRectF &boundingRect, - const QFontMetrics &fm) const + const QFontMetrics &fm, + const qreal fadeInOffset, + const qreal fadeOutOffset) const { AnnotationRects rects; - rects.annotationRect = boundingRect; rects.text = lineAnnotation(); + if (rects.text.isEmpty()) + return rects; + rects.fadeInRect = boundingRect; + rects.fadeInRect.setWidth(fadeInOffset); + rects.annotationRect = boundingRect; + rects.annotationRect.setLeft(rects.fadeInRect.right()); const bool drawIcon = !m_icon.isNull(); constexpr qreal margin = 1; - rects.iconRect = QRectF(boundingRect.left() + margin, boundingRect.top() + margin, 0, 0); - if (drawIcon) { - rects.iconRect.setHeight(boundingRect.height() - 2 * margin); + rects.iconRect = QRectF(rects.annotationRect.left(), boundingRect.top(), + 0, boundingRect.height()); + if (drawIcon) rects.iconRect.setWidth(rects.iconRect.height() * m_widthFactor); - } rects.textRect = QRectF(rects.iconRect.right() + margin, boundingRect.top(), qreal(fm.width(rects.text)), boundingRect.height()); rects.annotationRect.setRight(rects.textRect.right() + margin); @@ -165,6 +180,12 @@ TextMark::AnnotationRects TextMark::annotationRects(const QRectF &boundingRect, rects.textRect.setRight(boundingRect.right() - margin); rects.text = fm.elidedText(rects.text, Qt::ElideRight, int(rects.textRect.width())); rects.annotationRect.setRight(boundingRect.right()); + rects.fadeOutRect = QRectF(rects.annotationRect.topRight(), + rects.annotationRect.bottomRight()); + } else { + rects.fadeOutRect = boundingRect; + rects.fadeOutRect.setLeft(rects.annotationRect.right()); + rects.fadeOutRect.setWidth(fadeOutOffset); } return rects; } diff --git a/src/plugins/texteditor/textmark.h b/src/plugins/texteditor/textmark.h index ca484a85388..f744da7dc9b 100644 --- a/src/plugins/texteditor/textmark.h +++ b/src/plugins/texteditor/textmark.h @@ -64,15 +64,19 @@ public: int lineNumber() const; virtual void paintIcon(QPainter *painter, const QRect &rect) const; - virtual void paintAnnotation(QPainter *painter, QRectF *annotationRect) const; + virtual void paintAnnotation(QPainter &painter, QRectF *annotationRect, + const qreal fadeInOffset, const qreal fadeOutOffset) const; struct AnnotationRects { + QRectF fadeInRect; QRectF annotationRect; QRectF iconRect; QRectF textRect; + QRectF fadeOutRect; QString text; }; - virtual AnnotationRects annotationRects(const QRectF &boundingRect, const QFontMetrics &fm) const; + AnnotationRects annotationRects(const QRectF &boundingRect, const QFontMetrics &fm, + const qreal fadeInOffset, const qreal fadeOutOffset) const; /// called if the filename of the document changed virtual void updateFileName(const QString &fileName); virtual void updateLineNumber(int lineNumber); From a82c47d3079dab568f56098e3c74162852d9e561 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Thu, 20 Jul 2017 16:35:55 +0200 Subject: [PATCH 03/37] CppEditor: Remove invalid QTC_ASSERT This can be triggered by: 1. Put the cursor on some identifier 2. Type some e.g. a-z character and trigger Ctrl+Shift+R as fast as possible Typing the characters modifies the document and triggers the CppUseSelectionsUpdater asynchronously. The result comes in when we are already in local renaming mode, thus the assert triggers. Change-Id: I4ae7b2b4c259b3b1ef637f5272b0bda06b6db2ec Reviewed-by: David Schulz --- src/plugins/cppeditor/cpplocalrenaming.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cpplocalrenaming.cpp b/src/plugins/cppeditor/cpplocalrenaming.cpp index d14a5832f2b..fd989c782c8 100644 --- a/src/plugins/cppeditor/cpplocalrenaming.cpp +++ b/src/plugins/cppeditor/cpplocalrenaming.cpp @@ -70,7 +70,9 @@ CppLocalRenaming::CppLocalRenaming(TextEditor::TextEditorWidget *editorWidget) void CppLocalRenaming::updateSelectionsForVariableUnderCursor( const QList &selections) { - QTC_ASSERT(!isActive(), return); + if (isActive()) + return; + m_selections = selections; } From 2c9feb1f4b301e9a9228739a89c438bb7ff043f0 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Tue, 18 Jul 2017 15:06:13 +0200 Subject: [PATCH 04/37] C++: Add tests for MatchingText::contextAllowsAutoParentheses Change-Id: I4c2bdf55112f473770db1515bd412215685bfe04 Reviewed-by: David Schulz --- tests/unit/unittest/matchingtext-test.cpp | 180 ++++++++++++++++++++++ tests/unit/unittest/unittest.pro | 3 +- 2 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 tests/unit/unittest/matchingtext-test.cpp diff --git a/tests/unit/unittest/matchingtext-test.cpp b/tests/unit/unittest/matchingtext-test.cpp new file mode 100644 index 00000000000..daa702b328f --- /dev/null +++ b/tests/unit/unittest/matchingtext-test.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "googletest.h" + +#include + +#include +#include + +#include + +#include + +namespace { + +class Document { +public: + Document(const QString &documentText, char marker = '@') + { + QString text = documentText; + const int markerIndex = documentText.indexOf(marker); + if (markerIndex == -1) + return; + + text.replace(markerIndex, 1, ""); + + document.reset(new QTextDocument(text)); + cursor = QTextCursor(document.get()); + cursor.setPosition(markerIndex); + } + + std::unique_ptr document; + QTextCursor cursor; +}; + +using MT = CPlusPlus::MatchingText; +class MatchingText : public testing::Test {}; + +TEST_F(MatchingText, ContextAllowsAutoParentheses_ForNoInput) +{ + const Document document("@"); + + ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotInEmptyLine) +{ + const Document document("@"); + + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_Initializer) +{ + const Document document("Type object@"); + + ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_AfterFunctionDeclaratorSameLine) +{ + const Document document("void g() @"); + + ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +// TODO: Fix! +//TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_AfterFunctionDeclaratorNewLine) +//{ +// const Document document("void g()\n" +// "@"); + +// ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +//} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_AfterLambdaDeclarator) +{ + const Document document("[]() @"); + + ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +// TODO: This does not seem useful, remove. +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_BeforeOpeningCurlyBrace) +{ + const Document document("@{"); + + ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_BeforeClosingCurlyBrace) +{ + const Document document("@}"); + + ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_BeforeClosingBracket) +{ + const Document document("@]"); + + ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_BeforeClosingParen) +{ + const Document document("@)"); + + ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_BeforeSemicolon) +{ + const Document document("@;"); + + ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_BeforeComma) +{ + const Document document("@,"); + + ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotInCppComment) +{ + const Document document("// @"); + + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotInCppDoxygenComment) +{ + const Document document("//! @"); + + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +// TODO: Fix! +//TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeIndented) +//{ +// const Document document("if (true) @\n" +// " 1+1;"); + +// ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +//} + +// TODO: Fix! +//TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeNamespace) +//{ +// const Document document("namespace X @"); + +// ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +//} + +} // anonymous diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index c227eaede24..fb83baa8d8e 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -66,7 +66,8 @@ SOURCES += \ filepath-test.cpp \ sourcerangefilter-test.cpp \ clangqueryexamplehighlightmarker-test.cpp \ - clangqueryhighlightmarker-test.cpp + clangqueryhighlightmarker-test.cpp \ + matchingtext-test.cpp !isEmpty(LIBCLANG_LIBS) { SOURCES += \ From a6aa287720112c70c1363bcb46d55d438fe57eac Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Mon, 17 Jul 2017 12:57:23 +0200 Subject: [PATCH 05/37] C++: Fine-tune auto insertion of '}' Do not insert for these cases: * { * namespace X * if the next block is indented, like e.g.: if (e) g(); * on empty line if text before looks like a finished statement or scope opening/end Change-Id: Id9decc1e964a775724a929c2a3e79b5283105560 Reviewed-by: David Schulz --- src/libs/cplusplus/MatchingText.cpp | 225 +++++++++++++++++++-- src/libs/cplusplus/MatchingText.h | 8 +- src/plugins/cppeditor/cppautocompleter.cpp | 9 +- src/plugins/texteditor/autocompleter.cpp | 31 ++- src/plugins/texteditor/autocompleter.h | 2 + tests/unit/unittest/matchingtext-test.cpp | 127 +++++++++--- 6 files changed, 343 insertions(+), 59 deletions(-) diff --git a/src/libs/cplusplus/MatchingText.cpp b/src/libs/cplusplus/MatchingText.cpp index 3fdb573b918..e2f04e4f0f2 100644 --- a/src/libs/cplusplus/MatchingText.cpp +++ b/src/libs/cplusplus/MatchingText.cpp @@ -34,6 +34,8 @@ #include #include +#include + using namespace CPlusPlus; enum { MAX_NUM_LINES = 20 }; @@ -135,16 +137,215 @@ static const Token tokenAtPosition(const Tokens &tokens, const unsigned pos) return Token(); } +static int tokenIndexBeforePosition(const Tokens &tokens, unsigned pos) +{ + for (int i = tokens.size() - 1; i >= 0; --i) { + if (tokens[i].utf16charsBegin() < pos) + return i; + } + return -1; +} + +static bool isCursorAtEndOfLineButMaybeBeforeComment(const Tokens &tokens, int pos) +{ + int index = tokenIndexBeforePosition(tokens, uint(pos)); + if (index == -1 || index >= tokens.size()) + return false; + + do { + ++index; + } while (index < tokens.size() && tokens[index].isComment()); + + return index >= tokens.size(); +} + +// 10.6.1 Attribute syntax and semantics +// This does not handle alignas() since it is not needed for the namespace case. +static int skipAttributeSpecifierSequence(const Tokens &tokens, int index) +{ + // [[ attribute-using-prefixopt attribute-list ]] + if (index >= 1 && tokens[index].is(T_RBRACKET) && tokens[index - 1].is(T_RBRACKET)) { + // Skip everything within [[ ]] + for (int i = index - 2; i >= 0; --i) { + if (i >= 1 && tokens[i].is(T_LBRACKET) && tokens[i - 1].is(T_LBRACKET)) + return i - 2; + } + + return -1; + } + + return index; +} + +static int skipNamespaceName(const Tokens &tokens, int index) +{ + if (index >= tokens.size()) + return -1; + + if (!tokens[index].is(T_IDENTIFIER)) + return index; + + // Accept + // SomeName + // Some::Nested::Name + bool expectIdentifier = false; + for (int i = index - 1; i >= 0; --i) { + if (expectIdentifier) { + if (tokens[i].is(T_IDENTIFIER)) + expectIdentifier = false; + else + return -1; + } else if (tokens[i].is(T_COLON_COLON)) { + expectIdentifier = true; + } else { + return i; + } + } + + return index; +} + +// 10.3.1 Namespace definition +static bool isAfterNamespaceDefinition(const Tokens &tokens, int position) +{ + int index = tokenIndexBeforePosition(tokens, uint(position)); + if (index == -1) + return false; + + // Handle optional name + index = skipNamespaceName(tokens, index); + if (index == -1) + return false; + + // Handle optional attribute specifier sequence + index = skipAttributeSpecifierSequence(tokens, index); + if (index == -1) + return false; + + return index >= 0 && tokens[index].is(T_NAMESPACE); +} + +static int isEmptyOrWhitespace(const QString &text) +{ + return Utils::allOf(text, [](const QChar &c) {return c.isSpace(); }); +} + +static QTextBlock previousNonEmptyBlock(const QTextBlock ¤tBlock) +{ + QTextBlock block = currentBlock.previous(); + forever { + if (!block.isValid() || !isEmptyOrWhitespace(block.text())) + return block; + block = block.previous(); + } +} + +static QTextBlock nextNonEmptyBlock(const QTextBlock ¤tBlock) +{ + QTextBlock block = currentBlock.next(); + forever { + if (!block.isValid() || !isEmptyOrWhitespace(block.text())) + return block; + block = block.next(); + } +} + +static bool allowAutoClosingBraceAtEmptyLine( + const QTextBlock &block, + MatchingText::IsNextBlockDeeperIndented isNextDeeperIndented) +{ + QTextBlock previousBlock = previousNonEmptyBlock(block); + if (!previousBlock.isValid()) + return false; // Nothing before + + QTextBlock nextBlock = nextNonEmptyBlock(block); + if (!nextBlock.isValid()) + return true; // Nothing behind + + if (isNextDeeperIndented && isNextDeeperIndented(previousBlock)) + return false; // Before indented + + const QString trimmedText = previousBlock.text().trimmed(); + return !trimmedText.endsWith(';') + && !trimmedText.endsWith('{') + && !trimmedText.endsWith('}'); +} + +static Tokens getTokens(const QTextCursor &cursor, int &prevState) +{ + LanguageFeatures features; + features.qtEnabled = false; + features.qtKeywordsEnabled = false; + features.qtMocRunEnabled = false; + features.cxx11Enabled = true; + features.cxxEnabled = true; + features.c99Enabled = true; + features.objCEnabled = true; + + SimpleLexer tokenize; + tokenize.setLanguageFeatures(features); + + prevState = BackwardsScanner::previousBlockState(cursor.block()) & 0xFF; + return tokenize(cursor.block().text(), prevState); +} + +static QChar firstNonSpace(const QTextCursor &cursor) +{ + int position = cursor.position(); + QChar ch = cursor.document()->characterAt(position); + while (ch.isSpace()) + ch = cursor.document()->characterAt(++position); + + return ch; +} + +static bool allowAutoClosingBraceByLookahead(const QTextCursor &cursor) +{ + const QChar lookAhead = firstNonSpace(cursor); + if (lookAhead.isNull()) + return true; + + switch (lookAhead.unicode()) { + case ';': case ',': + case ')': case '}': case ']': + return true; + } + + return false; +} + +static bool allowAutoClosingBrace(const QTextCursor &cursor, + MatchingText::IsNextBlockDeeperIndented isNextIndented) +{ + if (MatchingText::isInCommentHelper(cursor)) + return false; + + const QTextBlock block = cursor.block(); + if (isEmptyOrWhitespace(block.text())) + return allowAutoClosingBraceAtEmptyLine(cursor.block(), isNextIndented); + + int prevState; + const Tokens tokens = getTokens(cursor, prevState); + if (isAfterNamespaceDefinition(tokens, cursor.positionInBlock())) + return false; + + if (isCursorAtEndOfLineButMaybeBeforeComment(tokens, cursor.positionInBlock())) + return !(isNextIndented && isNextIndented(block)); + + return allowAutoClosingBraceByLookahead(cursor); +} + bool MatchingText::contextAllowsAutoParentheses(const QTextCursor &cursor, - const QString &textToInsert) + const QString &textToInsert, + IsNextBlockDeeperIndented isNextIndented) { QChar ch; if (!textToInsert.isEmpty()) ch = textToInsert.at(0); - if (ch == QLatin1Char('{') && cursor.block().text().trimmed().isEmpty()) - return false; // User just might want to wrap up some lines. + if (ch == QLatin1Char('{')) + return allowAutoClosingBrace(cursor, isNextIndented); if (!shouldInsertMatchingText(cursor) && ch != QLatin1Char('\'') && ch != QLatin1Char('"')) return false; @@ -198,24 +399,6 @@ bool MatchingText::shouldInsertMatchingText(QChar lookAhead) } // switch } -static Tokens getTokens(const QTextCursor &cursor, int &prevState) -{ - LanguageFeatures features; - features.qtEnabled = false; - features.qtKeywordsEnabled = false; - features.qtMocRunEnabled = false; - features.cxx11Enabled = true; - features.cxxEnabled = true; - features.c99Enabled = true; - features.objCEnabled = true; - - SimpleLexer tokenize; - tokenize.setLanguageFeatures(features); - - prevState = BackwardsScanner::previousBlockState(cursor.block()) & 0xFF; - return tokenize(cursor.block().text(), prevState); -} - bool MatchingText::isInCommentHelper(const QTextCursor &cursor, Token *retToken) { int prevState = 0; diff --git a/src/libs/cplusplus/MatchingText.h b/src/libs/cplusplus/MatchingText.h index 59463917c41..b394e342af3 100644 --- a/src/libs/cplusplus/MatchingText.h +++ b/src/libs/cplusplus/MatchingText.h @@ -30,7 +30,10 @@ #include #include +#include + QT_FORWARD_DECLARE_CLASS(QTextCursor) +QT_FORWARD_DECLARE_CLASS(QTextBlock) QT_FORWARD_DECLARE_CLASS(QChar) namespace CPlusPlus { @@ -38,8 +41,11 @@ namespace CPlusPlus { class CPLUSPLUS_EXPORT MatchingText { public: + using IsNextBlockDeeperIndented = std::function; static bool contextAllowsAutoParentheses(const QTextCursor &cursor, - const QString &textToInsert); + const QString &textToInsert, + IsNextBlockDeeperIndented isNextIndented + = IsNextBlockDeeperIndented()); static bool contextAllowsAutoQuotes(const QTextCursor &cursor, const QString &textToInsert); static bool contextAllowsElectricCharacters(const QTextCursor &cursor); diff --git a/src/plugins/cppeditor/cppautocompleter.cpp b/src/plugins/cppeditor/cppautocompleter.cpp index a1b5ca5900b..2f6a2fc46f1 100644 --- a/src/plugins/cppeditor/cppautocompleter.cpp +++ b/src/plugins/cppeditor/cppautocompleter.cpp @@ -27,15 +27,20 @@ #include +#include + +#include #include using namespace CppEditor; using namespace Internal; bool CppAutoCompleter::contextAllowsAutoBrackets(const QTextCursor &cursor, - const QString &textToInsert) const + const QString &textToInsert) const { - return CPlusPlus::MatchingText::contextAllowsAutoParentheses(cursor, textToInsert); + const CPlusPlus::MatchingText::IsNextBlockDeeperIndented isIndented + = [this](const QTextBlock &b) { return isNextBlockIndented(b); }; + return CPlusPlus::MatchingText::contextAllowsAutoParentheses(cursor, textToInsert, isIndented); } bool CppAutoCompleter::contextAllowsAutoQuotes(const QTextCursor &cursor, diff --git a/src/plugins/texteditor/autocompleter.cpp b/src/plugins/texteditor/autocompleter.cpp index 8ac7bbb6b38..08ce56bd48b 100644 --- a/src/plugins/texteditor/autocompleter.cpp +++ b/src/plugins/texteditor/autocompleter.cpp @@ -150,6 +150,24 @@ bool AutoCompleter::isQuote(const QString &text) return text == QLatin1String("\"") || text == QLatin1String("'"); } +bool AutoCompleter::isNextBlockIndented(const QTextBlock ¤tBlock) const +{ + QTextBlock block = currentBlock; + int indentation = m_tabSettings.indentationColumn(block.text()); + + if (block.next().isValid()) { // not the last block + block = block.next(); + //skip all empty blocks + while (block.isValid() && m_tabSettings.onlySpace(block.text())) + block = block.next(); + if (block.isValid() + && m_tabSettings.indentationColumn(block.text()) > indentation) + return true; + } + + return false; +} + QString AutoCompleter::replaceSelection(QTextCursor &cursor, const QString &textToInsert) const { if (!cursor.hasSelection()) @@ -301,17 +319,8 @@ int AutoCompleter::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor) if (condition) {| statement; */ - int indentation = m_tabSettings.indentationColumn(block.text()); - - if (block.next().isValid()) { // not the last block - block = block.next(); - //skip all empty blocks - while (block.isValid() && m_tabSettings.onlySpace(block.text())) - block = block.next(); - if (block.isValid() - && m_tabSettings.indentationColumn(block.text()) > indentation) - return 0; - } + if (isNextBlockIndented(block)) + return 0; const QString &textToInsert = insertParagraphSeparator(cursor); int pos = cursor.position(); diff --git a/src/plugins/texteditor/autocompleter.h b/src/plugins/texteditor/autocompleter.h index 5d12b63b83a..4847f504762 100644 --- a/src/plugins/texteditor/autocompleter.h +++ b/src/plugins/texteditor/autocompleter.h @@ -31,6 +31,7 @@ #include QT_BEGIN_NAMESPACE +class QTextBlock; class QTextCursor; QT_END_NAMESPACE @@ -90,6 +91,7 @@ public: virtual QString insertParagraphSeparator(const QTextCursor &cursor) const; static bool isQuote(const QString &text); + bool isNextBlockIndented(const QTextBlock ¤tBlock) const; private: QString replaceSelection(QTextCursor &cursor, const QString &textToInsert) const; diff --git a/tests/unit/unittest/matchingtext-test.cpp b/tests/unit/unittest/matchingtext-test.cpp index daa702b328f..d5bfcaddefe 100644 --- a/tests/unit/unittest/matchingtext-test.cpp +++ b/tests/unit/unittest/matchingtext-test.cpp @@ -57,7 +57,12 @@ public: }; using MT = CPlusPlus::MatchingText; -class MatchingText : public testing::Test {}; +using IsNextBlockDeeperIndented = MT::IsNextBlockDeeperIndented; + +class MatchingText : public testing::Test { +protected: + const IsNextBlockDeeperIndented nextBlockIsIndented = [](const QTextBlock &) { return true; }; +}; TEST_F(MatchingText, ContextAllowsAutoParentheses_ForNoInput) { @@ -87,14 +92,22 @@ TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_AfterFunctionDeclar ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); } -// TODO: Fix! -//TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_AfterFunctionDeclaratorNewLine) -//{ -// const Document document("void g()\n" -// "@"); +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_AfterFunctionDeclaratorNewLine) +{ + const Document document("void g()\n" + "@"); -// ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); -//} + ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_AfterFunctionDeclaratorNewLineAndMore) +{ + const Document document("void g()\n" + "@\n" + "1+1;"); + + ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_AfterLambdaDeclarator) { @@ -103,12 +116,11 @@ TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_AfterLambdaDeclarat ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); } -// TODO: This does not seem useful, remove. -TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_BeforeOpeningCurlyBrace) +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeOpeningCurlyBrace) { const Document document("@{"); - ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); } TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_BeforeClosingCurlyBrace) @@ -160,21 +172,88 @@ TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotInCppDoxygenComm ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); } -// TODO: Fix! -//TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeIndented) -//{ -// const Document document("if (true) @\n" -// " 1+1;"); +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeIndented) +{ + const Document document("@\n" + " 1+1;"); -// ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); -//} + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{", nextBlockIsIndented)); +} -// TODO: Fix! -//TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeNamespace) -//{ -// const Document document("namespace X @"); +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeIndentedWithFollowingComment) +{ + const Document document("@\n // comment" + " 1+1;"); -// ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); -//} + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{", nextBlockIsIndented)); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeIndentedWithTextInFront) +{ + const Document document("if (true) @\n" + " 1+1;"); + + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{", nextBlockIsIndented)); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeIndentedOnEmptyLine1) +{ + const Document document("if (true)\n" + "@\n" + " 1+1;"); + + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{", nextBlockIsIndented)); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeIndentedOnEmptyLine2) +{ + const Document document("if (true)\n" + " @\n" + " 1+1;"); + + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{", nextBlockIsIndented)); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotInTheMiddle) +{ + const Document document("if (true) @ true;"); + + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeNamedNamespace) +{ + const Document document("namespace X @"); + + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeNamedNamespaceWithAttributeSpecifier) +{ + const Document document("namespace [[xyz]] X @"); + + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeUnnamedNamespace) +{ + const Document document("namespace @"); + + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeUnnamedNamespaceWithAttributeSpecifier) +{ + const Document document("namespace [[xyz]] @"); + + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeNestedNamespace) +{ + const Document document("namespace X::Y::Z @"); + + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} } // anonymous From 214f87b69b776741d9dc11a04a397158f86cfe99 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 21 Jul 2017 10:36:59 +0200 Subject: [PATCH 06/37] Doc: Describe renaming files when renaming symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the symbol is a class, and filenames contain the symbol, Qt Creator also offers to rename the files. Change-Id: Iba467cc4bf5ec6d4098973c9d391ffaff2f3bc4b Reviewed-by: André Hartmann Reviewed-by: Nikolai Kosjar --- doc/images/qtcreator-refactoring-replace.png | Bin 19564 -> 70727 bytes doc/src/editors/creator-editors.qdoc | 12 +++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/images/qtcreator-refactoring-replace.png b/doc/images/qtcreator-refactoring-replace.png index 4c62c5f0656377d3e1b769d023b674c10afc8ce1..d0fa9dec4754a34ea4fabb9701ca1c611d3df290 100644 GIT binary patch literal 70727 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ྯ=n-Uq@zFSqp7tl4bWrWKNHlk+9v?7GFm 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%0DWKOZ6;IS?!TNwVZE> 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 z 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 literal 19564 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 My85}Sb4q9e094*!@c;k- diff --git a/doc/src/editors/creator-editors.qdoc b/doc/src/editors/creator-editors.qdoc index 9b55aad11a3..26e77776ed3 100644 --- a/doc/src/editors/creator-editors.qdoc +++ b/doc/src/editors/creator-editors.qdoc @@ -1956,6 +1956,9 @@ \section1 Renaming Symbols + You can rename symbols in all files in a project. When you rename a class, + you can also change filenames that match the class name. + To rename a specific symbol in a Qt project: \list 1 @@ -1973,15 +1976,18 @@ \image qtcreator-refactoring-replace.png \li To replace all selected instances, enter the name of the new symbol - in the \uicontrol {Replace with} text box and click - \uicontrol Replace. + in the \uicontrol {Replace with} text box. To omit an instance, uncheck the check-box next to the instance. + \li If the symbol is a class, select the \uicontrol {Rename files} check + box to also change the filenames that match the class name. + + \li Select \uicontrol Replace. + \note This action replaces all selected instances of the symbol in all files listed in the \uicontrol {Search Results} pane. You cannot undo this action. - \endlist \note Renaming local symbols does not open the \uicontrol {Search Results} From a4cb8479a3d9cbb4991b6886cfaa075f6991d08d Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 21 Jul 2017 14:23:50 +0200 Subject: [PATCH 07/37] QmlDesigner: Fix flickering move cursor The check for selectedItemCursorInMovableArea has to be the first check, because otherwise we might change back to the selection tool if e.g. the item list is empty. This leads to a flickering cursor and bad usabilty. Change-Id: I0ea82cd1c4bf83cde0b173ab08f19bd04b1128c0 Reviewed-by: Tim Jenssen --- .../components/formeditor/movetool.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/plugins/qmldesigner/components/formeditor/movetool.cpp b/src/plugins/qmldesigner/components/formeditor/movetool.cpp index fba74d9b3cb..5fb29ac88d4 100644 --- a/src/plugins/qmldesigner/components/formeditor/movetool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/movetool.cpp @@ -124,23 +124,26 @@ void MoveTool::mouseMoveEvent(const QList &itemList, void MoveTool::hoverMoveEvent(const QList &itemList, QGraphicsSceneMouseEvent * event) { - if (itemList.isEmpty()) { - view()->changeToSelectionTool(); - return; - } - ResizeHandleItem* resizeHandle = ResizeHandleItem::fromGraphicsItem(itemList.first()); if (resizeHandle) { view()->changeToResizeTool(); return; } + if (view()->hasSingleSelectedModelNode() && selectedItemCursorInMovableArea(event->scenePos())) + return; + + if (itemList.isEmpty()) { + view()->changeToSelectionTool(); + return; + } + if (!topSelectedItemIsMovable(itemList)) { view()->changeToSelectionTool(); return; } - if (view()->hasSingleSelectedModelNode() && !selectedItemCursorInMovableArea(event->scenePos())) { + if (view()->hasSingleSelectedModelNode()) { view()->changeToSelectionTool(); return; } From 561a50e3a107ba8c8540732d460e3590dd263730 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 21 Jul 2017 15:22:23 +0200 Subject: [PATCH 08/37] QmlDesigner: Increase the size of resize handle This makes it less likely to accidentally move an item instead of resizing it. Change-Id: I6102a05c50a68d50ea9e4a316f48089186b3a373 Reviewed-by: Tim Jenssen --- .../qmldesigner/components/formeditor/resizehandleitem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/formeditor/resizehandleitem.cpp b/src/plugins/qmldesigner/components/formeditor/resizehandleitem.cpp index abdbd2d60b2..d40e4067f92 100644 --- a/src/plugins/qmldesigner/components/formeditor/resizehandleitem.cpp +++ b/src/plugins/qmldesigner/components/formeditor/resizehandleitem.cpp @@ -50,7 +50,7 @@ void ResizeHandleItem::setHandlePosition(const QPointF & globalPosition, const Q QRectF ResizeHandleItem::boundingRect() const { - return QRectF(- 3., - 3., 7., 7.); + return QRectF(- 5., - 5., 9., 9.); } void ResizeHandleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /* option */, QWidget * /* widget */) From f073c39b86ac53995d9121905f4c5837a5b79174 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Sun, 23 Jul 2017 08:01:16 +0300 Subject: [PATCH 09/37] Git: Minor cleanup in grep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I2a686b6f56947d3fbb6dc70757e539bf4f274bff Reviewed-by: André Hartmann --- src/plugins/git/gitgrep.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index 3c0096921f0..9e09c7a90a5 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -141,11 +141,11 @@ public: void exec() { - QStringList arguments; - arguments << "-c" << "color.grep.match=bold red" - << "grep" << "-zn" - << "--no-full-name" - << "--color=always"; + GitClient *client = GitPlugin::client(); + QStringList arguments = { + "-c", "color.grep.match=bold red", + "grep", "-zn", "--no-full-name", "--color=always" + }; if (!(m_parameters.flags & FindCaseSensitively)) arguments << "-i"; if (m_parameters.flags & FindWholeWords) @@ -168,7 +168,7 @@ public: return QString(":!" + filter); }); arguments << "--" << filterArgs << exclusionArgs; - QScopedPointer command(GitPlugin::client()->createCommand(m_directory)); + QScopedPointer command(client->createCommand(m_directory)); command->addFlags(VcsCommand::SilentOutput | VcsCommand::SuppressFailMessage); command->setProgressiveOutput(true); QFutureWatcher watcher; @@ -176,7 +176,7 @@ public: connect(&watcher, &QFutureWatcher::canceled, command.data(), &VcsCommand::cancel); connect(command.data(), &VcsCommand::stdOutText, this, &GitGrepRunner::read); - SynchronousProcessResponse resp = command->runCommand(GitPlugin::client()->vcsBinary(), arguments, 0); + SynchronousProcessResponse resp = command->runCommand(client->vcsBinary(), arguments, 0); switch (resp.result) { case SynchronousProcessResponse::TerminatedAbnormally: case SynchronousProcessResponse::StartFailed: From 2a555a0da728b5afc43d0ed5d4626e583dbf7307 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 21 Jul 2017 15:58:51 +0200 Subject: [PATCH 10/37] Update qbs submodule To HEAD of 1.9 branch. Change-Id: I9561a75c9ef9ceb2b331d7244aded508a596e037 Reviewed-by: Joerg Bornemann --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index ed9b5833894..4db6418abae 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit ed9b5833894f24e2cfbf4c432497d48844a97d1d +Subproject commit 4db6418abaefe23795984a48025ede6a54ba34de From 625129d29c38c8902a3f654d58da9d4cb1a5a712 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 27 Jun 2017 15:15:43 +0200 Subject: [PATCH 11/37] AutoTest: Fix appending test results with the same name If two test cases had the same name but came from a different executable the results pane still might have shown any later one (badly) cascaded inside the first one. Avoid this by providing an additional unique information (the respective executable for the test case) Task-number: QTCREATORBUG-18502 Change-Id: Ib071e389758b6269a9a90cc4c4afbcf86ca583ac Reviewed-by: David Schulz --- src/plugins/autotest/gtest/gtestoutputreader.cpp | 7 ++++--- src/plugins/autotest/gtest/gtestoutputreader.h | 1 + src/plugins/autotest/gtest/gtestresult.cpp | 5 +++++ src/plugins/autotest/gtest/gtestresult.h | 1 + src/plugins/autotest/qtest/qttestoutputreader.cpp | 3 ++- src/plugins/autotest/qtest/qttestoutputreader.h | 1 + src/plugins/autotest/qtest/qttestresult.cpp | 9 +++++++-- src/plugins/autotest/qtest/qttestresult.h | 1 + src/plugins/autotest/testresult.cpp | 14 +++++++++++--- src/plugins/autotest/testresult.h | 5 ++++- src/plugins/autotest/testresultmodel.cpp | 4 +++- 11 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/plugins/autotest/gtest/gtestoutputreader.cpp b/src/plugins/autotest/gtest/gtestoutputreader.cpp index 96382f5f896..a455282476c 100644 --- a/src/plugins/autotest/gtest/gtestoutputreader.cpp +++ b/src/plugins/autotest/gtest/gtestoutputreader.cpp @@ -41,6 +41,7 @@ static QString constructSourceFilePath(const QString &path, const QString &fileP GTestOutputReader::GTestOutputReader(const QFutureInterface &futureInterface, QProcess *testApplication, const QString &buildDirectory) : TestOutputReader(futureInterface, testApplication, buildDirectory) + , m_executable(testApplication ? testApplication->program() : QString()) { } @@ -75,7 +76,7 @@ void GTestOutputReader::processOutput(const QByteArray &outputLine) m_futureInterface.reportResult(testResult); m_description.clear(); } else if (disabledTests.exactMatch(line)) { - TestResultPtr testResult = TestResultPtr(new GTestResult()); + TestResultPtr testResult = TestResultPtr(new GTestResult); testResult->setResult(Result::MessageDisabledTests); int disabled = disabledTests.cap(1).toInt(); testResult->setDescription(tr("You have %n disabled test(s).", 0, disabled)); @@ -106,7 +107,7 @@ void GTestOutputReader::processOutput(const QByteArray &outputLine) m_futureInterface.reportResult(testResult); } else if (newTestSetStarts.exactMatch(line)) { m_currentTestSet = newTestSetStarts.cap(1); - TestResultPtr testResult = TestResultPtr(new GTestResult()); + TestResultPtr testResult = TestResultPtr(new GTestResult); testResult->setResult(Result::MessageCurrentTest); testResult->setDescription(tr("Entering test set %1").arg(m_currentTestSet)); m_futureInterface.reportResult(testResult); @@ -156,7 +157,7 @@ void GTestOutputReader::processOutput(const QByteArray &outputLine) GTestResult *GTestOutputReader::createDefaultResult() const { - GTestResult *result = new GTestResult(m_currentTestName); + GTestResult *result = new GTestResult(m_executable, m_currentTestName); result->setTestSetName(m_currentTestSet); result->setIteration(m_iteration); return result; diff --git a/src/plugins/autotest/gtest/gtestoutputreader.h b/src/plugins/autotest/gtest/gtestoutputreader.h index 0ed2bf878cb..5cedffed006 100644 --- a/src/plugins/autotest/gtest/gtestoutputreader.h +++ b/src/plugins/autotest/gtest/gtestoutputreader.h @@ -47,6 +47,7 @@ protected: private: GTestResult *createDefaultResult() const; + QString m_executable; QString m_currentTestName; QString m_currentTestSet; QString m_description; diff --git a/src/plugins/autotest/gtest/gtestresult.cpp b/src/plugins/autotest/gtest/gtestresult.cpp index 604f5cedaac..cbccaea837e 100644 --- a/src/plugins/autotest/gtest/gtestresult.cpp +++ b/src/plugins/autotest/gtest/gtestresult.cpp @@ -33,6 +33,11 @@ GTestResult::GTestResult(const QString &name) { } +GTestResult::GTestResult(const QString &executable, const QString &name) + : TestResult(executable, name) +{ +} + const QString GTestResult::outputString(bool selected) const { const QString &desc = description(); diff --git a/src/plugins/autotest/gtest/gtestresult.h b/src/plugins/autotest/gtest/gtestresult.h index 74a8e1e9c3b..491fe41662f 100644 --- a/src/plugins/autotest/gtest/gtestresult.h +++ b/src/plugins/autotest/gtest/gtestresult.h @@ -34,6 +34,7 @@ class GTestResult : public TestResult { public: explicit GTestResult(const QString &name = QString()); + GTestResult(const QString &executable, const QString &name); const QString outputString(bool selected) const override; void setTestSetName(const QString &testSetName) { m_testSetName = testSetName; } diff --git a/src/plugins/autotest/qtest/qttestoutputreader.cpp b/src/plugins/autotest/qtest/qttestoutputreader.cpp index e7c7725d02e..d1999bba395 100644 --- a/src/plugins/autotest/qtest/qttestoutputreader.cpp +++ b/src/plugins/autotest/qtest/qttestoutputreader.cpp @@ -132,6 +132,7 @@ QtTestOutputReader::QtTestOutputReader(const QFutureInterface &fu QProcess *testApplication, const QString &buildDirectory, OutputMode mode) : TestOutputReader(futureInterface, testApplication, buildDirectory) + , m_executable(testApplication ? testApplication->program() : QString()) , m_mode(mode) { } @@ -419,7 +420,7 @@ void QtTestOutputReader::processSummaryFinishOutput() QtTestResult *QtTestOutputReader::createDefaultResult() const { - QtTestResult *result = new QtTestResult(m_className); + QtTestResult *result = new QtTestResult(m_executable, m_className); result->setFunctionName(m_testCase); result->setDataTag(m_dataTag); return result; diff --git a/src/plugins/autotest/qtest/qttestoutputreader.h b/src/plugins/autotest/qtest/qttestoutputreader.h index 28305160642..75f0b9a42ea 100644 --- a/src/plugins/autotest/qtest/qttestoutputreader.h +++ b/src/plugins/autotest/qtest/qttestoutputreader.h @@ -78,6 +78,7 @@ private: }; CDATAMode m_cdataMode = None; + QString m_executable; QString m_className; QString m_testCase; QString m_formerTestCase; diff --git a/src/plugins/autotest/qtest/qttestresult.cpp b/src/plugins/autotest/qtest/qttestresult.cpp index 50d64d72901..68c9f2bf3f3 100644 --- a/src/plugins/autotest/qtest/qttestresult.cpp +++ b/src/plugins/autotest/qtest/qttestresult.cpp @@ -35,6 +35,11 @@ QtTestResult::QtTestResult(const QString &className) { } +QtTestResult::QtTestResult(const QString &executable, const QString &className) + : TestResult(executable, className) +{ +} + const QString QtTestResult::outputString(bool selected) const { const QString &desc = description(); @@ -101,14 +106,14 @@ bool QtTestResult::isIntermediateFor(const TestResult *other) const QTC_ASSERT(other, return false); const QtTestResult *qtOther = static_cast(other); return m_dataTag == qtOther->m_dataTag && m_function == qtOther->m_function - && name() == qtOther->name(); + && name() == qtOther->name() && executable() == qtOther->executable(); } TestResult *QtTestResult::createIntermediateResultFor(const TestResult *other) { QTC_ASSERT(other, return nullptr); const QtTestResult *qtOther = static_cast(other); - QtTestResult *intermediate = new QtTestResult(qtOther->name()); + QtTestResult *intermediate = new QtTestResult(qtOther->executable(), qtOther->name()); intermediate->m_function = qtOther->m_function; intermediate->m_dataTag = qtOther->m_dataTag; // intermediates will be needed only for data tags diff --git a/src/plugins/autotest/qtest/qttestresult.h b/src/plugins/autotest/qtest/qttestresult.h index 216b6ef3327..c7c9e8ae2a9 100644 --- a/src/plugins/autotest/qtest/qttestresult.h +++ b/src/plugins/autotest/qtest/qttestresult.h @@ -34,6 +34,7 @@ class QtTestResult : public TestResult { public: explicit QtTestResult(const QString &className = QString()); + QtTestResult(const QString &executable, const QString &className); const QString outputString(bool selected) const override; void setFunctionName(const QString &functionName) { m_function = functionName; } diff --git a/src/plugins/autotest/testresult.cpp b/src/plugins/autotest/testresult.cpp index bfef7164034..fce6f05c856 100644 --- a/src/plugins/autotest/testresult.cpp +++ b/src/plugins/autotest/testresult.cpp @@ -47,6 +47,12 @@ TestResult::TestResult(const QString &name) { } +TestResult::TestResult(const QString &executable, const QString &name) + : m_executable(executable) + , m_name(name) +{ +} + const QString TestResult::outputString(bool selected) const { return selected ? m_description : m_description.split('\n').first(); @@ -173,19 +179,21 @@ bool TestResult::isMessageCaseStart(const Result::Type type) bool TestResult::isDirectParentOf(const TestResult *other, bool * /*needsIntermediate*/) const { QTC_ASSERT(other, return false); - return m_name == other->m_name; + return !m_executable.isEmpty() && m_executable == other->m_executable + && m_name == other->m_name; } bool TestResult::isIntermediateFor(const TestResult *other) const { QTC_ASSERT(other, return false); - return m_name == other->m_name; + return !m_executable.isEmpty() && m_executable == other->m_executable + && m_name == other->m_name; } TestResult *TestResult::createIntermediateResultFor(const TestResult *other) { QTC_ASSERT(other, return nullptr); - TestResult *intermediate = new TestResult(other->m_name); + TestResult *intermediate = new TestResult(other->m_executable, other->m_name); return intermediate; } diff --git a/src/plugins/autotest/testresult.h b/src/plugins/autotest/testresult.h index e53e6fcce41..267b7be4196 100644 --- a/src/plugins/autotest/testresult.h +++ b/src/plugins/autotest/testresult.h @@ -69,12 +69,14 @@ enum Type { class TestResult { public: - explicit TestResult(); + TestResult(); explicit TestResult(const QString &name); + TestResult(const QString &executable, const QString &name); virtual ~TestResult() {} virtual const QString outputString(bool selected) const; + QString executable() const { return m_executable; } QString name() const { return m_name; } Result::Type result() const { return m_result; } QString description() const { return m_description; } @@ -97,6 +99,7 @@ public: virtual TestResult *createIntermediateResultFor(const TestResult *other); private: + QString m_executable; QString m_name; Result::Type m_result = Result::Invalid; QString m_description; diff --git a/src/plugins/autotest/testresultmodel.cpp b/src/plugins/autotest/testresultmodel.cpp index 3bfdba93573..ec996f1b353 100644 --- a/src/plugins/autotest/testresultmodel.cpp +++ b/src/plugins/autotest/testresultmodel.cpp @@ -295,11 +295,13 @@ TestResultItem *TestResultModel::findParentItemFor(const TestResultItem *item, TestResultItem *root = startItem ? const_cast(startItem) : nullptr; const TestResult *result = item->testResult(); const QString &name = result->name(); + const QString &executable = result->executable(); if (root == nullptr && !name.isEmpty()) { for (int row = rootItem()->childCount() - 1; row >= 0; --row) { TestResultItem *tmp = static_cast(rootItem()->childAt(row)); - if (tmp->testResult()->name() == name) { + auto tmpTestResult = tmp->testResult(); + if (tmpTestResult->executable() == executable && tmpTestResult->name() == name) { root = tmp; break; } From b4ca318383d0de704f9053cb979a1b35bebe3324 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 10 Jul 2017 15:02:24 +0200 Subject: [PATCH 12/37] AutoTest: Improve test results summary items display Instead of letting warn prevail over pass and fail over warn just add warn as additional visual marker at the icons and keep the original test result. Task-number: QTCREATORBUG-18311 Change-Id: Ia67288fa84598b02c20fc1019799b1bb9282d63e Reviewed-by: David Schulz --- src/plugins/autotest/autotesticons.h | 8 +++++ src/plugins/autotest/testresult.cpp | 7 ++-- src/plugins/autotest/testresult.h | 3 +- src/plugins/autotest/testresultdelegate.cpp | 4 +-- src/plugins/autotest/testresultmodel.cpp | 37 +++++++++++++++------ 5 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/plugins/autotest/autotesticons.h b/src/plugins/autotest/autotesticons.h index b278509dbbc..1420be31ad8 100644 --- a/src/plugins/autotest/autotesticons.h +++ b/src/plugins/autotest/autotesticons.h @@ -68,6 +68,14 @@ const Utils::Icon RESULT_MESSAGEDEBUG({ const Utils::Icon RESULT_MESSAGEWARN({ {":/utils/images/filledcircle.png", Utils::Theme::OutputPanes_TestWarnTextColor}}, Utils::Icon::Tint); +const Utils::Icon RESULT_MESSAGEPASSWARN({ + {":/utils/images/filledcircle.png", Utils::Theme::OutputPanes_TestPassTextColor}, + {":/utils/images/iconoverlay_warning.png", Utils::Theme::OutputPanes_TestWarnTextColor}}, + Utils::Icon::Tint | Utils::Icon::PunchEdges); +const Utils::Icon RESULT_MESSAGEFAILWARN({ + {":/utils/images/filledcircle.png", Utils::Theme::OutputPanes_TestFailTextColor}, + {":/utils/images/iconoverlay_warning.png", Utils::Theme::OutputPanes_TestWarnTextColor}}, + Utils::Icon::Tint | Utils::Icon::PunchEdges); const Utils::Icon RESULT_MESSAGEFATAL({ {":/utils/images/filledcircle.png", Utils::Theme::OutputPanes_TestFatalTextColor}}, Utils::Icon::Tint); diff --git a/src/plugins/autotest/testresult.cpp b/src/plugins/autotest/testresult.cpp index fce6f05c856..2dcd9dda70a 100644 --- a/src/plugins/autotest/testresult.cpp +++ b/src/plugins/autotest/testresult.cpp @@ -103,9 +103,11 @@ QString TestResult::resultToString(const Result::Type type) switch (type) { case Result::Pass: case Result::MessageTestCaseSuccess: + case Result::MessageTestCaseSuccessWarn: return QString("PASS"); case Result::Fail: case Result::MessageTestCaseFail: + case Result::MessageTestCaseFailWarn: return QString("FAIL"); case Result::ExpectedFail: return QString("XFAIL"); @@ -120,7 +122,6 @@ QString TestResult::resultToString(const Result::Type type) case Result::MessageInfo: return QString("INFO"); case Result::MessageWarn: - case Result::MessageTestCaseWarn: return QString("WARN"); case Result::MessageFatal: return QString("FATAL"); @@ -172,8 +173,8 @@ QColor TestResult::colorForType(const Result::Type type) bool TestResult::isMessageCaseStart(const Result::Type type) { return type == Result::MessageTestCaseStart || type == Result::MessageTestCaseSuccess - || type == Result::MessageTestCaseFail || type == Result::MessageTestCaseWarn - || type == Result::MessageIntermediate; + || type == Result::MessageTestCaseFail || type == Result::MessageTestCaseSuccessWarn + || type == Result::MessageTestCaseFailWarn || type == Result::MessageIntermediate; } bool TestResult::isDirectParentOf(const TestResult *other, bool * /*needsIntermediate*/) const diff --git a/src/plugins/autotest/testresult.h b/src/plugins/autotest/testresult.h index 267b7be4196..a7414f85d36 100644 --- a/src/plugins/autotest/testresult.h +++ b/src/plugins/autotest/testresult.h @@ -55,8 +55,9 @@ enum Type { MessageDisabledTests, MessageTestCaseStart, MessageTestCaseSuccess, - MessageTestCaseWarn, + MessageTestCaseSuccessWarn, MessageTestCaseFail, + MessageTestCaseFailWarn, MessageTestCaseEnd, MessageIntermediate, MessageCurrentTest, INTERNAL_MESSAGES_END = MessageCurrentTest, diff --git a/src/plugins/autotest/testresultdelegate.cpp b/src/plugins/autotest/testresultdelegate.cpp index fb273384401..9bd01925848 100644 --- a/src/plugins/autotest/testresultdelegate.cpp +++ b/src/plugins/autotest/testresultdelegate.cpp @@ -41,8 +41,8 @@ const static int outputLimit = 100000; static bool isSummaryItem(Result::Type type) { - return type == Result::MessageTestCaseSuccess || type == Result::MessageTestCaseFail - || type == Result::MessageTestCaseWarn; + return type == Result::MessageTestCaseSuccess || type == Result::MessageTestCaseSuccessWarn + || type == Result::MessageTestCaseFail || type == Result::MessageTestCaseFailWarn; } TestResultDelegate::TestResultDelegate(QObject *parent) diff --git a/src/plugins/autotest/testresultmodel.cpp b/src/plugins/autotest/testresultmodel.cpp index ec996f1b353..a41fc64b011 100644 --- a/src/plugins/autotest/testresultmodel.cpp +++ b/src/plugins/autotest/testresultmodel.cpp @@ -61,6 +61,8 @@ static QIcon testResultIcon(Result::Type result) { Icons::RESULT_MESSAGEWARN.icon(), Icons::RESULT_MESSAGEFATAL.icon(), Icons::RESULT_MESSAGEFATAL.icon(), // System gets same handling as Fatal for now + Icons::RESULT_MESSAGEPASSWARN.icon(), + Icons::RESULT_MESSAGEFAILWARN.icon(), }; // provide an icon for unknown?? if (result < 0 || result >= Result::MessageInternal) { @@ -69,8 +71,10 @@ static QIcon testResultIcon(Result::Type result) { return icons[Result::Pass]; case Result::MessageTestCaseFail: return icons[Result::Fail]; - case Result::MessageTestCaseWarn: - return icons[Result::MessageWarn]; + case Result::MessageTestCaseSuccessWarn: + return icons[13]; + case Result::MessageTestCaseFailWarn: + return icons[14]; default: return QIcon(); } @@ -103,6 +107,7 @@ void TestResultItem::updateResult() return; Result::Type newResult = Result::MessageTestCaseSuccess; + bool withWarning = false; for (Utils::TreeItem *child : *this) { const TestResult *current = static_cast(child)->testResult(); if (current) { @@ -111,21 +116,28 @@ void TestResultItem::updateResult() case Result::MessageFatal: case Result::UnexpectedPass: case Result::MessageTestCaseFail: - m_testResult->setResult(Result::MessageTestCaseFail); - return; + newResult = Result::MessageTestCaseFail; + break; case Result::ExpectedFail: case Result::MessageWarn: case Result::Skip: case Result::BlacklistedFail: case Result::BlacklistedPass: - case Result::MessageTestCaseWarn: - newResult = Result::MessageTestCaseWarn; + case Result::MessageTestCaseSuccessWarn: + case Result::MessageTestCaseFailWarn: + withWarning = true; break; default: {} } } } - m_testResult->setResult(newResult); + if (withWarning) { + m_testResult->setResult(newResult == Result::MessageTestCaseSuccess + ? Result::MessageTestCaseSuccessWarn + : Result::MessageTestCaseFailWarn); + } else { + m_testResult->setResult(newResult); + } } void TestResultItem::updateIntermediateChildren() @@ -346,8 +358,9 @@ void TestResultFilterModel::enableAllResultTypes() << Result::MessageFatal << Result::Invalid << Result::BlacklistedPass << Result::BlacklistedFail << Result::Benchmark << Result::MessageIntermediate << Result::MessageCurrentTest << Result::MessageTestCaseStart - << Result::MessageTestCaseSuccess << Result::MessageTestCaseWarn - << Result::MessageTestCaseFail << Result::MessageTestCaseEnd + << Result::MessageTestCaseSuccess << Result::MessageTestCaseSuccessWarn + << Result::MessageTestCaseFail << Result::MessageTestCaseFailWarn + << Result::MessageTestCaseEnd << Result::MessageInfo << Result::MessageSystem; invalidateFilter(); } @@ -395,7 +408,8 @@ bool TestResultFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &s case Result::MessageTestCaseSuccess: return m_enabled.contains(Result::Pass); case Result::MessageTestCaseFail: - case Result::MessageTestCaseWarn: + case Result::MessageTestCaseSuccessWarn: + case Result::MessageTestCaseFailWarn: return acceptTestCaseResult(index); default: return m_enabled.contains(resultType); @@ -409,7 +423,8 @@ bool TestResultFilterModel::acceptTestCaseResult(const QModelIndex &srcIndex) co Result::Type type = m_sourceModel->testResult(child)->result(); if (type == Result::MessageTestCaseSuccess) type = Result::Pass; - if (type == Result::MessageTestCaseFail || type == Result::MessageTestCaseWarn) { + if (type == Result::MessageTestCaseFail || type == Result::MessageTestCaseFailWarn + || type == Result::MessageTestCaseSuccessWarn) { if (acceptTestCaseResult(child)) return true; } else if (m_enabled.contains(type)) { From 9652e85b3d0a782b6e253d7cd7e8ccfa98c6a572 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 24 Jul 2017 13:22:39 +0200 Subject: [PATCH 13/37] Doc: Describe new ways of marking code errors when using Clang Change-Id: I9b2d8ee52e83c60b7c6d46d2b5e8e830536e6bdb Reviewed-by: Nikolai Kosjar --- doc/images/qtcreator-semanticerror-clang.png | Bin 0 -> 33662 bytes doc/images/qtcreator-syntaxerror-clang.png | Bin 0 -> 31551 bytes doc/src/editors/creator-editors.qdoc | 28 +++++++++++++++++-- 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 doc/images/qtcreator-semanticerror-clang.png create mode 100644 doc/images/qtcreator-syntaxerror-clang.png diff --git a/doc/images/qtcreator-semanticerror-clang.png b/doc/images/qtcreator-semanticerror-clang.png new file mode 100644 index 0000000000000000000000000000000000000000..9980485832b097fd7e89797477233a7d3700ef98 GIT binary patch literal 33662 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 literal 0 HcmV?d00001 diff --git a/doc/images/qtcreator-syntaxerror-clang.png b/doc/images/qtcreator-syntaxerror-clang.png new file mode 100644 index 0000000000000000000000000000000000000000..8beee1832fa5f94346a273b1f94754da0b0bc6fe GIT binary patch literal 31551 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

n;G&x6gM>;G;3 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 vY(X=b@ \uicontrol Options > \uicontrol {Text Editor} > + \uicontrol Display > \uicontrol {Annotations next to lines}, and then + select whether to display the annotations directly next to the code, + aligned to the right of the code, or in the right margin. + + If you hide the annotations by deselecting the check box, you can move the + mouse pointer over an icon to view them. \section1 Checking JSON Data Structure + You can run static checks on the QML and JavaScript code in + your project to find common problems. + \QC validates instances of JSON entities against \l{http://tools.ietf.org/html/draft-zyp-json-schema-03} {A JSON Media Type for Describing the Structure and Meaning of JSON Documents}. From 4335f1184e0433b24c51343f90c1418181ec179d Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Mon, 24 Jul 2017 12:07:22 +0200 Subject: [PATCH 14/37] Core: Replace guards by assert Change-Id: I116d7fece2a96dbfc9adad0905bc08d8ea4ca40e Reviewed-by: Eike Ziller --- src/plugins/coreplugin/find/findtoolwindow.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/coreplugin/find/findtoolwindow.cpp b/src/plugins/coreplugin/find/findtoolwindow.cpp index 8647b7b2e94..05704437ebb 100644 --- a/src/plugins/coreplugin/find/findtoolwindow.cpp +++ b/src/plugins/coreplugin/find/findtoolwindow.cpp @@ -264,12 +264,12 @@ void FindToolWindow::setCurrentFilter(int index) void FindToolWindow::acceptAndGetParameters(QString *term, IFindFilter **filter) { - if (filter) - *filter = 0; + QTC_ASSERT(filter, return); + *filter = 0; Find::updateFindCompletion(m_ui.searchTerm->text()); int index = m_ui.filterList->currentIndex(); QString searchTerm = m_ui.searchTerm->text(); - if (filter && index >= 0) + if (index >= 0) *filter = m_filters.at(index); if (term) *term = searchTerm; From 6b2d6e7965aedbb71856b660883cc7676a78faf0 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 21 Jul 2017 13:53:33 +0200 Subject: [PATCH 15/37] CppEditor: Cancel waiting for use selections if revision changed Not sure whether this can happen at all, but if it can, we should not make the UI unusable. Change-Id: I1a40630d0c1f057e20a33b2c755e1fd5aea0b003 Reviewed-by: David Schulz --- src/plugins/cppeditor/cppuseselectionsupdater.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/cppeditor/cppuseselectionsupdater.cpp b/src/plugins/cppeditor/cppuseselectionsupdater.cpp index 81e1436ccde..4e13fee5975 100644 --- a/src/plugins/cppeditor/cppuseselectionsupdater.cpp +++ b/src/plugins/cppeditor/cppuseselectionsupdater.cpp @@ -94,6 +94,7 @@ void CppUseSelectionsUpdater::update(CallType callType) m_runnerWatcher->setFuture(cppEditorDocument->cursorInfo(params)); } else { // synchronous case + const int startRevision = cppEditorDocument->document()->revision(); QFuture future = cppEditorDocument->cursorInfo(params); // QFuture::waitForFinished seems to block completely, not even @@ -102,6 +103,7 @@ void CppUseSelectionsUpdater::update(CallType callType) if (future.isCanceled()) return; + QTC_ASSERT(startRevision == cppEditorDocument->document()->revision(), return); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } From 15793d33186e521cc633505622b44ed71e78dfe5 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Mon, 24 Jul 2017 14:15:22 +0200 Subject: [PATCH 16/37] Clang: Make clangCompleteAt.sh work with standard headers "clang -cc1" is the frontend only and as such it does not have any include paths set. Use -Xclang instead. [1] https://clang.llvm.org/docs/FAQ.html#id2 Change-Id: I372601cae5c672562b63fa07ed9e638e984fdd58 Reviewed-by: Marco Bubke --- scripts/clangCompleteAt.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/clangCompleteAt.sh b/scripts/clangCompleteAt.sh index e80fbd623a4..18f225a9207 100755 --- a/scripts/clangCompleteAt.sh +++ b/scripts/clangCompleteAt.sh @@ -94,7 +94,7 @@ runCodeCompletion() if [ -n "${CINDEXTEST_EXEC}" ]; then command="${CINDEXTEST_EXEC} -code-completion-at=${FILE}:${LINE}:${COLUMN} ${FILE}" else - command="${CLANG_EXEC} -cc1 -code-completion-at ${FILE}:${LINE}:${COLUMN} ${FILE}" + command="${CLANG_EXEC} -fsyntax-only -Xclang -code-completion-at -Xclang ${FILE}:${LINE}:${COLUMN} ${FILE}" fi echo "Command: $command" eval $command From 9b5d6546b8282f237214115285fc864b87f2d857 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 20 Jul 2017 17:06:36 +0200 Subject: [PATCH 17/37] Clang: Remove pointer arguments from output argument Non constant pointers are used many times as non output arguments, so you get misleading information. Task-number: QTCREATORBUG-18591 Change-Id: Ic5f987db44ad63a0b1a38fd59cd807db5f2acc8f Reviewed-by: Nikolai Kosjar --- src/tools/clangbackend/ipcsource/clangtype.cpp | 2 +- tests/unit/unittest/data/highlightingmarks.cpp | 6 +++--- tests/unit/unittest/highlightingmarks-test.cpp | 14 ++++++++++++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/tools/clangbackend/ipcsource/clangtype.cpp b/src/tools/clangbackend/ipcsource/clangtype.cpp index dd0e192f7a3..8fc09d8c4af 100644 --- a/src/tools/clangbackend/ipcsource/clangtype.cpp +++ b/src/tools/clangbackend/ipcsource/clangtype.cpp @@ -76,7 +76,7 @@ bool Type::isReferencingConstant() const bool Type::isOutputArgument() const { - return (isPointer() || isLValueReference()) && !pointeeType().isConstant(); + return isLValueReference() && !pointeeType().isConstant(); } bool Type::isBuiltinType() const diff --git a/tests/unit/unittest/data/highlightingmarks.cpp b/tests/unit/unittest/data/highlightingmarks.cpp index a954df3e973..7c78ddf1965 100644 --- a/tests/unit/unittest/data/highlightingmarks.cpp +++ b/tests/unit/unittest/data/highlightingmarks.cpp @@ -482,12 +482,12 @@ void f25() NonConstPointerArgument(x); } -void ConstPointerArgument(const int *argument); - +void PointerToConstArgument(const int *argument); +void ConstPointerArgument(int *const argument); void f26() { int *x; - + PointerToConstArgument(x); ConstPointerArgument(x); } diff --git a/tests/unit/unittest/highlightingmarks-test.cpp b/tests/unit/unittest/highlightingmarks-test.cpp index e72d25c9711..c22c3e2df88 100644 --- a/tests/unit/unittest/highlightingmarks-test.cpp +++ b/tests/unit/unittest/highlightingmarks-test.cpp @@ -998,7 +998,17 @@ TEST_F(HighlightingMarks, NonConstPointerArgument) infos[1]; ASSERT_THAT(infos[2], - HasTwoTypes(HighlightingType::LocalVariable, HighlightingType::OutputArgument)); + HasOnlyType(HighlightingType::LocalVariable)); +} + +TEST_F(HighlightingMarks, PointerToConstArgument) +{ + const auto infos = translationUnit.highlightingMarksInRange(sourceRange(490, 31)); + + infos[1]; + + ASSERT_THAT(infos[2], + HasOnlyType(HighlightingType::LocalVariable)); } TEST_F(HighlightingMarks, ConstPointerArgument) @@ -1048,7 +1058,7 @@ TEST_F(HighlightingMarks, NonConstPointerArgumentAsExpression) infos[1]; ASSERT_THAT(infos[3], - HasTwoTypes(HighlightingType::LocalVariable, HighlightingType::OutputArgument)); + HasOnlyType(HighlightingType::LocalVariable)); } TEST_F(HighlightingMarks, NonConstPointerArgumentAsInstanceWithMember) From 9428624fc1d24492ef71b3f738edb4598b53df53 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 19 Jul 2017 10:43:47 +0200 Subject: [PATCH 18/37] Clang: Tool tips for clang query diagnostics If you hover a diagnostics in for a clang query you get now a simple tool tip. Change-Id: I6352dd3d4b9a33c183e69037eac903469b90eea4 Reviewed-by: Tim Jenssen --- ...amicastmatcherdiagnosticcontextcontainer.h | 2 +- ...icastmatcherdiagnosticmessagecontainer.cpp | 2 +- ...amicastmatcherdiagnosticmessagecontainer.h | 2 +- .../clangqueryhighlighter.cpp | 12 + .../clangrefactoring/clangqueryhighlighter.h | 6 + .../clangqueryhighlightmarker.h | 79 ++++++ .../clangqueryhoverhandler.cpp | 60 ++++ .../clangrefactoring/clangqueryhoverhandler.h | 46 +++ .../clangquerytexteditorwidget.cpp | 11 +- .../clangquerytexteditorwidget.h | 5 + .../clangrefactoring/clangrefactoring.pro | 6 +- src/plugins/texteditor/texteditor.cpp | 5 + src/plugins/texteditor/texteditor.h | 2 + .../source/clangquery.cpp | 2 +- .../source/clangquery.h | 2 +- .../clangqueryhighlightmarker-test.cpp | 261 +++++++++++++++++- 16 files changed, 492 insertions(+), 11 deletions(-) create mode 100644 src/plugins/clangrefactoring/clangqueryhoverhandler.cpp create mode 100644 src/plugins/clangrefactoring/clangqueryhoverhandler.h diff --git a/src/libs/clangbackendipc/dynamicastmatcherdiagnosticcontextcontainer.h b/src/libs/clangbackendipc/dynamicastmatcherdiagnosticcontextcontainer.h index 61d7e2fff56..c220aa23777 100644 --- a/src/libs/clangbackendipc/dynamicastmatcherdiagnosticcontextcontainer.h +++ b/src/libs/clangbackendipc/dynamicastmatcherdiagnosticcontextcontainer.h @@ -55,7 +55,7 @@ public: return m_contextType; } - Utils::SmallString contextTypeText() const; + CMBIPC_EXPORT Utils::SmallString contextTypeText() const; const Utils::SmallStringVector &arguments() const { diff --git a/src/libs/clangbackendipc/dynamicastmatcherdiagnosticmessagecontainer.cpp b/src/libs/clangbackendipc/dynamicastmatcherdiagnosticmessagecontainer.cpp index af4de3e058d..e17ecd4da90 100644 --- a/src/libs/clangbackendipc/dynamicastmatcherdiagnosticmessagecontainer.cpp +++ b/src/libs/clangbackendipc/dynamicastmatcherdiagnosticmessagecontainer.cpp @@ -33,8 +33,8 @@ namespace ClangBackEnd { QDebug operator<<(QDebug debug, const DynamicASTMatcherDiagnosticMessageContainer &container) { debug.nospace() << "DynamicASTMatcherDiagnosticMessageContainer(" - << container.sourceRange() << ", " << container.errorTypeText() << ", " + << container.sourceRange() << ", " << container.arguments() << ")"; diff --git a/src/libs/clangbackendipc/dynamicastmatcherdiagnosticmessagecontainer.h b/src/libs/clangbackendipc/dynamicastmatcherdiagnosticmessagecontainer.h index 8f9581872d6..07a21af605f 100644 --- a/src/libs/clangbackendipc/dynamicastmatcherdiagnosticmessagecontainer.h +++ b/src/libs/clangbackendipc/dynamicastmatcherdiagnosticmessagecontainer.h @@ -55,7 +55,7 @@ public: return m_errorType; } - Utils::SmallString errorTypeText() const; + CMBIPC_EXPORT Utils::SmallString errorTypeText() const; const Utils::SmallStringVector &arguments() const { diff --git a/src/plugins/clangrefactoring/clangqueryhighlighter.cpp b/src/plugins/clangrefactoring/clangqueryhighlighter.cpp index 5f9e72d4be5..d00bf82d297 100644 --- a/src/plugins/clangrefactoring/clangqueryhighlighter.cpp +++ b/src/plugins/clangrefactoring/clangqueryhighlighter.cpp @@ -72,6 +72,18 @@ bool ClangQueryHighlighter::hasDiagnostics() const return m_marker.hasMessagesOrContexts(); } +ClangBackEnd::DynamicASTMatcherDiagnosticMessageContainers +ClangQueryHighlighter::messagesForLineAndColumn(uint line, uint column) const +{ + return m_marker.messagesForLineAndColumn(line, column); +} + +ClangBackEnd::DynamicASTMatcherDiagnosticContextContainers +ClangQueryHighlighter::contextsForLineAndColumn(uint line, uint column) const +{ + return m_marker.contextsForLineAndColumn(line, column); +} + void ClangQueryHighlighter::highlightBlock(const QString &text) { int currentLineNumber = currentBlock().blockNumber() + 1; diff --git a/src/plugins/clangrefactoring/clangqueryhighlighter.h b/src/plugins/clangrefactoring/clangqueryhighlighter.h index 977f91fd117..7e96a1a5f90 100644 --- a/src/plugins/clangrefactoring/clangqueryhighlighter.h +++ b/src/plugins/clangrefactoring/clangqueryhighlighter.h @@ -44,6 +44,12 @@ public: bool hasDiagnostics() const; + ClangBackEnd::DynamicASTMatcherDiagnosticMessageContainers + messagesForLineAndColumn(uint line, uint column) const; + + ClangBackEnd::DynamicASTMatcherDiagnosticContextContainers + contextsForLineAndColumn(uint line, uint column) const; + protected: void highlightBlock(const QString &text) override; diff --git a/src/plugins/clangrefactoring/clangqueryhighlightmarker.h b/src/plugins/clangrefactoring/clangqueryhighlightmarker.h index 8f53d59538f..6ef61627b78 100644 --- a/src/plugins/clangrefactoring/clangqueryhighlightmarker.h +++ b/src/plugins/clangrefactoring/clangqueryhighlightmarker.h @@ -250,6 +250,85 @@ public: return !m_messages.empty() || !m_contexts.empty(); } + static + bool isAfterStartColumn(const SourceRange &sourceRange, uint line, uint column) + { + return sourceRange.start().line() == line && sourceRange.start().column() <= column; + } + + static + bool isBeforeEndColumn(const SourceRange &sourceRange, uint line, uint column) + { + return sourceRange.end().line() == line && sourceRange.end().column() >= column; + } + + static + bool isInBetweenLine(const SourceRange &sourceRange, uint line) + { + return sourceRange.start().line() < line && sourceRange.end().line() > line; + } + + static + bool isSingleLine(const SourceRange &sourceRange) + { + return sourceRange.start().line() == sourceRange.end().line(); + } + + static + bool isInsideMultiLine(const SourceRange &sourceRange, uint line, uint column) + { + return !isSingleLine(sourceRange) + && (isAfterStartColumn(sourceRange, line, column) + || isInBetweenLine(sourceRange, line) + || isBeforeEndColumn(sourceRange, line, column)); + } + + static + bool isInsideSingleLine(const SourceRange &sourceRange, uint line, uint column) + { + return isSingleLine(sourceRange) + && isAfterStartColumn(sourceRange, line, column) + && isBeforeEndColumn(sourceRange, line, column); + } + + static + bool isInsideRange(const SourceRange &sourceRange, uint line, uint column) + { + return isInsideSingleLine(sourceRange, line, column) + || isInsideMultiLine(sourceRange, line, column); + } + + Messages messagesForLineAndColumn(uint line, uint column) const + { + Messages messages; + + auto underPosition = [=] (const Message &message) { + return ClangQueryHighlightMarker::isInsideRange(message.sourceRange(), line, column); + }; + + std::copy_if(m_messages.begin(), + m_messages.end(), + std::back_inserter(messages), + underPosition); + + return messages; + } + + Contexts contextsForLineAndColumn(uint line, uint column) const + { + Contexts contexts; + + auto underPosition = [=] (const Context &context) { + return ClangQueryHighlightMarker::isInsideRange(context.sourceRange(), line, column); + }; + + std::copy_if(m_contexts.begin(), + m_contexts.end(), + std::back_inserter(contexts), + underPosition); + + return contexts; + } private: Contexts m_contexts; diff --git a/src/plugins/clangrefactoring/clangqueryhoverhandler.cpp b/src/plugins/clangrefactoring/clangqueryhoverhandler.cpp new file mode 100644 index 00000000000..47ca0dbe791 --- /dev/null +++ b/src/plugins/clangrefactoring/clangqueryhoverhandler.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "clangqueryhoverhandler.h" + +#include "clangqueryhighlighter.h" + +#include + +#include + +namespace ClangRefactoring { + +ClangQueryHoverHandler::ClangQueryHoverHandler(ClangQueryHighlighter *highligher) + : m_highligher(highligher) +{ +} + +void ClangQueryHoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget, int position) +{ + using Messages = ClangBackEnd::DynamicASTMatcherDiagnosticMessageContainers; + using Contexts = ClangBackEnd::DynamicASTMatcherDiagnosticContextContainers; + + QTextCursor textCursor = editorWidget->textCursor(); + textCursor.setPosition(position); + int line = textCursor.blockNumber() + 1; + int column = textCursor.columnNumber() + 1; + + Messages messages = m_highligher->messagesForLineAndColumn(uint(line), uint(column)); + Contexts contexts = m_highligher->contextsForLineAndColumn(uint(line), uint(column)); + + if (!messages.empty()) + setToolTip(QString("%1: %2").arg(messages[0].errorTypeText()).arg(messages[0].arguments().join(", "))); + else if (!contexts.empty()) + setToolTip(QString("%1: %2").arg(contexts[0].contextTypeText()).arg(contexts[0].arguments().join(", "))); +} + +} // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/clangqueryhoverhandler.h b/src/plugins/clangrefactoring/clangqueryhoverhandler.h new file mode 100644 index 00000000000..7a93bcbf5d3 --- /dev/null +++ b/src/plugins/clangrefactoring/clangqueryhoverhandler.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +namespace ClangRefactoring { + +class ClangQueryHighlighter; + +class ClangQueryHoverHandler : public TextEditor::BaseHoverHandler +{ +public: + ClangQueryHoverHandler(ClangQueryHighlighter *highligher); + +protected: + void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int position) override; + +private: + ClangQueryHighlighter *m_highligher; +}; + +} // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/clangquerytexteditorwidget.cpp b/src/plugins/clangrefactoring/clangquerytexteditorwidget.cpp index 7ca9d902545..2d0552680c9 100644 --- a/src/plugins/clangrefactoring/clangquerytexteditorwidget.cpp +++ b/src/plugins/clangrefactoring/clangquerytexteditorwidget.cpp @@ -26,19 +26,24 @@ #include "clangquerytexteditorwidget.h" #include "clangqueryhighlighter.h" +#include "clangqueryhoverhandler.h" #include namespace ClangRefactoring { ClangQueryTextEditorWidget::ClangQueryTextEditorWidget(QWidget *parent) - : BaseClangQueryTextEditorWidget(parent) + : BaseClangQueryTextEditorWidget(parent), + m_syntaxHighlighter(new ClangQueryHighlighter), + m_hoverHandler(std::make_unique(m_syntaxHighlighter)) { - m_syntaxHighlighter = new ClangQueryHighlighter; - textDocument()->setSyntaxHighlighter(m_syntaxHighlighter); + + addHoverHandler(m_hoverHandler.get()); } +ClangQueryTextEditorWidget::~ClangQueryTextEditorWidget() = default; + ClangQueryHighlighter *ClangQueryTextEditorWidget::syntaxHighlighter() const { return m_syntaxHighlighter; diff --git a/src/plugins/clangrefactoring/clangquerytexteditorwidget.h b/src/plugins/clangrefactoring/clangquerytexteditorwidget.h index 85dace14323..a221eb03fe0 100644 --- a/src/plugins/clangrefactoring/clangquerytexteditorwidget.h +++ b/src/plugins/clangrefactoring/clangquerytexteditorwidget.h @@ -27,9 +27,12 @@ #include "baseclangquerytexteditorwidget.h" +#include + namespace ClangRefactoring { class ClangQueryHighlighter; +class ClangQueryHoverHandler; class ClangQueryTextEditorWidget : public BaseClangQueryTextEditorWidget { @@ -37,11 +40,13 @@ class ClangQueryTextEditorWidget : public BaseClangQueryTextEditorWidget public: ClangQueryTextEditorWidget(QWidget *parent); + ~ClangQueryTextEditorWidget(); ClangQueryHighlighter *syntaxHighlighter() const; private: ClangQueryHighlighter *m_syntaxHighlighter; + std::unique_ptr m_hoverHandler; }; } // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/clangrefactoring.pro b/src/plugins/clangrefactoring/clangrefactoring.pro index 1a8d16e3e39..918398bef0f 100644 --- a/src/plugins/clangrefactoring/clangrefactoring.pro +++ b/src/plugins/clangrefactoring/clangrefactoring.pro @@ -14,7 +14,8 @@ HEADERS += \ clangqueryprojectsfindfilterwidget.h \ clangqueryexampletexteditorwidget.h \ clangquerytexteditorwidget.h \ - baseclangquerytexteditorwidget.h + baseclangquerytexteditorwidget.h \ + clangqueryhoverhandler.h SOURCES += \ clangrefactoringplugin.cpp \ @@ -24,7 +25,8 @@ SOURCES += \ clangqueryprojectsfindfilterwidget.cpp \ clangqueryexampletexteditorwidget.cpp \ clangquerytexteditorwidget.cpp \ - baseclangquerytexteditorwidget.cpp + baseclangquerytexteditorwidget.cpp \ + clangqueryhoverhandler.cpp FORMS += \ clangqueryprojectsfindfilter.ui diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 692faa1c509..120e43f46ca 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -5339,6 +5339,11 @@ void TextEditorWidget::showDefaultContextMenu(QContextMenuEvent *e, Id menuConte menu.exec(e->globalPos()); } +void TextEditorWidget::addHoverHandler(BaseHoverHandler *handler) +{ + d->m_hoverHandlers.append(handler); +} + void TextEditorWidget::extraAreaLeaveEvent(QEvent *) { d->extraAreaPreviousMarkTooltipRequestedLine = -1; diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index 0c2e83e1e87..f6fb8644045 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -512,6 +512,8 @@ protected: virtual void finalizeInitializationAfterDuplication(TextEditorWidget *) {} static QTextCursor flippedCursor(const QTextCursor &cursor); + void addHoverHandler(BaseHoverHandler *handler); + public: struct Link { diff --git a/src/tools/clangrefactoringbackend/source/clangquery.cpp b/src/tools/clangrefactoringbackend/source/clangquery.cpp index be93b61a1a6..b625e9e197f 100644 --- a/src/tools/clangrefactoringbackend/source/clangquery.cpp +++ b/src/tools/clangrefactoringbackend/source/clangquery.cpp @@ -92,7 +92,7 @@ SourceRangesContainer ClangQuery::takeSourceRanges() return std::move(sourceRangesContainer); } -std::vector ClangQuery::takeDiagnosticContainers() +DynamicASTMatcherDiagnosticContainers ClangQuery::takeDiagnosticContainers() { return std::move(diagnosticContainers_); } diff --git a/src/tools/clangrefactoringbackend/source/clangquery.h b/src/tools/clangrefactoringbackend/source/clangquery.h index 20b38a7ab10..faa5821ca3b 100644 --- a/src/tools/clangrefactoringbackend/source/clangquery.h +++ b/src/tools/clangrefactoringbackend/source/clangquery.h @@ -58,7 +58,7 @@ public: void findLocations(); SourceRangesContainer takeSourceRanges(); - std::vector takeDiagnosticContainers(); + DynamicASTMatcherDiagnosticContainers takeDiagnosticContainers(); private: void parseDiagnostics(const clang::ast_matchers::dynamic::Diagnostics &diagnostics); diff --git a/tests/unit/unittest/clangqueryhighlightmarker-test.cpp b/tests/unit/unittest/clangqueryhighlightmarker-test.cpp index 01d9f848f26..05e657b9eaa 100644 --- a/tests/unit/unittest/clangqueryhighlightmarker-test.cpp +++ b/tests/unit/unittest/clangqueryhighlightmarker-test.cpp @@ -32,12 +32,16 @@ namespace { using testing::AllOf; using testing::Contains; +using testing::ElementsAre; +using testing::Pointwise; using testing::IsEmpty; using testing::Not; using testing::InSequence; using testing::_; using SourceRange = ClangBackEnd::V2::SourceRangeContainer; +using Message = ClangBackEnd::DynamicASTMatcherDiagnosticMessageContainer; +using Context = ClangBackEnd::DynamicASTMatcherDiagnosticContextContainer; using Messages = ClangBackEnd::DynamicASTMatcherDiagnosticMessageContainers; using Contexts = ClangBackEnd::DynamicASTMatcherDiagnosticContextContainers; using Marker = ClangRefactoring::ClangQueryHighlightMarker; @@ -54,7 +58,6 @@ protected: QTextCharFormat contextTextFormat; MockSyntaxHighlighter highlighter; Marker marker{highlighter}; - }; TEST_F(ClangQueryHighlightMarker, NoCallForNoMessagesAndContexts) @@ -120,6 +123,262 @@ TEST_F(ClangQueryHighlightMarker, CallForMessagesAndContextForAMultiLine) marker.highlightBlock(3, " ) "); } +TEST_F(ClangQueryHighlightMarker, NoMessagesIfEmpty) +{ + Messages messages; + Contexts contexts; + marker.setMessagesAndContexts(std::move(messages), std::move(contexts)); + + auto foundMessages = marker.messagesForLineAndColumn(1, 1); + + ASSERT_THAT(foundMessages, IsEmpty()); +} + +TEST_F(ClangQueryHighlightMarker, NoMessagesForBeforePosition) +{ + Messages messages{{{1, 1, 5, 0, 3, 3, 0}, + ErrorType::RegistryMatcherNotFound, + {"foo"}}}; + Contexts contexts; + marker.setMessagesAndContexts(std::move(messages), std::move(contexts)); + + auto foundMessages = marker.messagesForLineAndColumn(1, 4); + + ASSERT_THAT(foundMessages, IsEmpty()); +} + +TEST_F(ClangQueryHighlightMarker, NoMessagesForAfterPosition) +{ + Messages messages{{{1, 1, 5, 0, 3, 3, 0}, + ErrorType::RegistryMatcherNotFound, + {"foo"}}}; + Contexts contexts; + marker.setMessagesAndContexts(std::move(messages), std::move(contexts)); + + auto foundMessages = marker.messagesForLineAndColumn(3, 4); + + ASSERT_THAT(foundMessages, IsEmpty()); +} + +TEST_F(ClangQueryHighlightMarker, OneMessagesForInsidePosition) +{ + Message message{{1, 1, 5, 0, 3, 3, 0}, + ErrorType::RegistryMatcherNotFound, + {"foo"}}; + Messages messages{message.clone()}; + Contexts contexts; + marker.setMessagesAndContexts(std::move(messages), std::move(contexts)); + + auto foundMessages = marker.messagesForLineAndColumn(2, 3); + + ASSERT_THAT(foundMessages, ElementsAre(message)); +} + +TEST_F(ClangQueryHighlightMarker, NoMessagesForOutsidePosition) +{ + Message message{{1, 1, 5, 0, 3, 3, 0}, + ErrorType::RegistryMatcherNotFound, + {"foo"}}; + Messages messages{message.clone()}; + Contexts contexts; + marker.setMessagesAndContexts(std::move(messages), std::move(contexts)); + + auto foundMessages = marker.messagesForLineAndColumn(3, 4); + + ASSERT_THAT(foundMessages, IsEmpty()); +} + +TEST_F(ClangQueryHighlightMarker, AfterStartColumnBeforeLine) +{ + SourceRange sourceRange{1, 2, 5, 0, 3, 3, 0}; + + bool isAfterStartColumn = marker.isInsideRange(sourceRange, 1, 6); + + ASSERT_FALSE(isAfterStartColumn); +} + +TEST_F(ClangQueryHighlightMarker, AfterStartColumnBeforeColumn) +{ + SourceRange sourceRange{1, 2, 5, 0, 3, 3, 0}; + + bool isAfterStartColumn = marker.isInsideRange(sourceRange, 2, 4); + + ASSERT_FALSE(isAfterStartColumn); +} + +TEST_F(ClangQueryHighlightMarker, AfterStartColumnAtColumn) +{ + SourceRange sourceRange{1, 2, 5, 0, 3, 3, 0}; + + bool isAfterStartColumn = marker.isInsideRange(sourceRange, 2, 5); + + ASSERT_TRUE(isAfterStartColumn); +} + +TEST_F(ClangQueryHighlightMarker, AfterStartColumnAfterColumn) +{ + SourceRange sourceRange{1, 2, 5, 0, 3, 3, 0}; + + bool isAfterStartColumn = marker.isInsideRange(sourceRange, 2, 6); + + ASSERT_TRUE(isAfterStartColumn); +} + +TEST_F(ClangQueryHighlightMarker, BeforeEndColumnAfterLine) +{ + SourceRange sourceRange{1, 2, 5, 0, 3, 3, 0}; + + bool isBeforeEndColumn = marker.isInsideRange(sourceRange, 4, 1); + + ASSERT_FALSE(isBeforeEndColumn); +} + +TEST_F(ClangQueryHighlightMarker, BeforeEndColumnAfterColumn) +{ + SourceRange sourceRange{1, 2, 5, 0, 3, 3, 0}; + + bool isBeforeEndColumn = marker.isInsideRange(sourceRange, 3, 4); + + ASSERT_FALSE(isBeforeEndColumn); +} + +TEST_F(ClangQueryHighlightMarker, BeforeEndColumnAtColumn) +{ + SourceRange sourceRange{1, 2, 5, 0, 3, 3, 0}; + + bool isBeforeEndColumn = marker.isInsideRange(sourceRange, 3, 3); + + ASSERT_TRUE(isBeforeEndColumn); +} + +TEST_F(ClangQueryHighlightMarker, BeforeEndColumnBeforeColumn) +{ + SourceRange sourceRange{1, 2, 5, 0, 3, 3, 0}; + + bool isBeforeEndColumn = marker.isInsideRange(sourceRange, 3, 2); + + ASSERT_TRUE(isBeforeEndColumn); +} + +TEST_F(ClangQueryHighlightMarker, InBetweenLineBeforeLine) +{ + SourceRange sourceRange{1, 2, 5, 0, 3, 3, 0}; + + bool isInBetween = marker.isInsideRange(sourceRange, 1, 6); + + ASSERT_FALSE(isInBetween); +} + +TEST_F(ClangQueryHighlightMarker, InBetweenLineAfterLine) +{ + SourceRange sourceRange{1, 2, 5, 0, 4, 3, 0}; + + bool isInBetween = marker.isInsideRange(sourceRange, 5, 1); + + ASSERT_FALSE(isInBetween); +} + +TEST_F(ClangQueryHighlightMarker, InBetweenLine) +{ + SourceRange sourceRange{1, 2, 5, 0, 4, 3, 0}; + + bool isInBetween = marker.isInsideRange(sourceRange, 3, 1); + + ASSERT_TRUE(isInBetween); +} + +TEST_F(ClangQueryHighlightMarker, SingleLineBefore) +{ + SourceRange sourceRange{1, 2, 5, 0, 2, 10, 0}; + + bool isInRange = marker.isInsideRange(sourceRange, 2, 4); + + ASSERT_FALSE(isInRange); +} + +TEST_F(ClangQueryHighlightMarker, SingleLineAfter) +{ + SourceRange sourceRange{1, 2, 5, 0, 2, 10, 0}; + + bool isInRange = marker.isInsideRange(sourceRange, 2, 11); + + ASSERT_FALSE(isInRange); +} + +TEST_F(ClangQueryHighlightMarker, SingleLineInRange) +{ + SourceRange sourceRange{1, 2, 5, 0, 2, 10, 0}; + + bool isInRange = marker.isInsideRange(sourceRange, 2, 6); + + ASSERT_TRUE(isInRange); +} + +TEST_F(ClangQueryHighlightMarker, NoContextsIfEmpty) +{ + Messages messages; + Contexts contexts; + marker.setMessagesAndContexts(std::move(messages), std::move(contexts)); + + auto foundContexts = marker.contextsForLineAndColumn(1, 1); + + ASSERT_THAT(foundContexts, IsEmpty()); +} + +TEST_F(ClangQueryHighlightMarker, NoContextsForBeforePosition) +{ + Messages messages; + Contexts contexts{{{1, 1, 5, 0, 3, 3, 0}, + ContextType::MatcherArg, + {"foo"}}}; + marker.setMessagesAndContexts(std::move(messages), std::move(contexts)); + + auto foundContexts = marker.contextsForLineAndColumn(1, 4); + + ASSERT_THAT(foundContexts, IsEmpty()); +} + +TEST_F(ClangQueryHighlightMarker, NoContextsForAfterPosition) +{ + Messages messages; + Contexts contexts{{{1, 1, 5, 0, 3, 3, 0}, + ContextType::MatcherArg, + {"foo"}}}; + marker.setMessagesAndContexts(std::move(messages), std::move(contexts)); + + auto foundContexts = marker.contextsForLineAndColumn(3, 4); + + ASSERT_THAT(foundContexts, IsEmpty()); +} + +TEST_F(ClangQueryHighlightMarker, OneContextsForInsidePosition) +{ + Context context{{1, 1, 5, 0, 3, 3, 0}, + ContextType::MatcherArg, + {"foo"}}; + Messages messages; + Contexts contexts{context.clone()}; + marker.setMessagesAndContexts(std::move(messages), std::move(contexts)); + + auto foundContexts = marker.contextsForLineAndColumn(2, 3); + + ASSERT_THAT(foundContexts, ElementsAre(context)); +} + +TEST_F(ClangQueryHighlightMarker, NoContextsForOutsidePosition) +{ + Context context{{1, 1, 5, 0, 3, 3, 0}, + ContextType::MatcherArg, + {"foo"}}; + Messages messages; + Contexts contexts{context.clone()}; + marker.setMessagesAndContexts(std::move(messages), std::move(contexts)); + + auto foundContexts = marker.contextsForLineAndColumn(3, 4); + + ASSERT_THAT(foundContexts, IsEmpty()); +} + void ClangQueryHighlightMarker::SetUp() { messageTextFormat.setFontItalic(true); From 05a77a39a1ea69d5e8a83023d609f9a0764e7789 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 24 Jul 2017 12:57:25 +0200 Subject: [PATCH 19/37] Clang: Make C++17 default for clang queries We don't want users to stop to use new features. Change-Id: I7c63f236a8c0059e6db6904b7ceef4d78da6cf42 Reviewed-by: Tim Jenssen --- src/plugins/clangrefactoring/clangqueryprojectsfindfilter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.cpp b/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.cpp index 2289746db34..d4e210c04e8 100644 --- a/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.cpp +++ b/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.cpp @@ -85,7 +85,7 @@ void ClangQueryProjectsFindFilter::requestSourceRangesAndDiagnostics(const QStri ClangBackEnd::RequestSourceRangesAndDiagnosticsForQueryMessage message(queryText, {ClangBackEnd::FilePath(filePath), exampleContent, - {"cc", toNative(filePath)}}); + {"cc", "-std=c++1z", toNative(filePath)}}); m_server.requestSourceRangesAndDiagnosticsForQueryMessage(std::move(message)); } From edbb656f2d48450731fca08cc1fa0709db0707d7 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 20 Jul 2017 16:43:16 +0200 Subject: [PATCH 20/37] Clang: Add field prefix for HighlightingMark Change-Id: I6cbd091f65ed931fbc31707c09b832ad782de03f Reviewed-by: Nikolai Kosjar --- .../ipcsource/highlightingmark.cpp | 140 +++++++++--------- .../clangbackend/ipcsource/highlightingmark.h | 28 ++-- 2 files changed, 84 insertions(+), 84 deletions(-) diff --git a/src/tools/clangbackend/ipcsource/highlightingmark.cpp b/src/tools/clangbackend/ipcsource/highlightingmark.cpp index 58a8a298ce1..03dd894a694 100644 --- a/src/tools/clangbackend/ipcsource/highlightingmark.cpp +++ b/src/tools/clangbackend/ipcsource/highlightingmark.cpp @@ -43,69 +43,69 @@ HighlightingMark::HighlightingMark(const CXCursor &cxCursor, CXToken *cxToken, CXTranslationUnit cxTranslationUnit, std::vector ¤tOutputArgumentRanges) - : currentOutputArgumentRanges(¤tOutputArgumentRanges), - originalCursor(cxCursor) + : m_currentOutputArgumentRanges(¤tOutputArgumentRanges), + m_originalCursor(cxCursor) { const SourceRange sourceRange = clang_getTokenExtent(cxTranslationUnit, *cxToken); const auto start = sourceRange.start(); const auto end = sourceRange.end(); - line = start.line(); - column = start.column(); - offset = start.offset(); - length = end.offset() - start.offset(); - collectKinds(cxTranslationUnit, cxToken, originalCursor); + m_line = start.line(); + m_column = start.column(); + m_offset = start.offset(); + m_length = end.offset() - start.offset(); + collectKinds(cxTranslationUnit, cxToken, m_originalCursor); } HighlightingMark::HighlightingMark(uint line, uint column, uint length, HighlightingTypes types) - : line(line), - column(column), - length(length), - types(types) + : m_line(line), + m_column(column), + m_length(length), + m_types(types) { } HighlightingMark::HighlightingMark(uint line, uint column, uint length, HighlightingType type) - : line(line), - column(column), - length(length), - types(HighlightingTypes()) + : m_line(line), + m_column(column), + m_length(length), + m_types(HighlightingTypes()) { - types.mainHighlightingType = type; + m_types.mainHighlightingType = type; } bool HighlightingMark::hasInvalidMainType() const { - return types.mainHighlightingType == HighlightingType::Invalid; + return m_types.mainHighlightingType == HighlightingType::Invalid; } bool HighlightingMark::hasMainType(HighlightingType type) const { - return types.mainHighlightingType == type; + return m_types.mainHighlightingType == type; } bool HighlightingMark::hasMixinType(HighlightingType type) const { - auto found = std::find(types.mixinHighlightingTypes.begin(), - types.mixinHighlightingTypes.end(), + auto found = std::find(m_types.mixinHighlightingTypes.begin(), + m_types.mixinHighlightingTypes.end(), type); - return found != types.mixinHighlightingTypes.end(); + return found != m_types.mixinHighlightingTypes.end(); } bool HighlightingMark::hasOnlyType(HighlightingType type) const { - return types.mixinHighlightingTypes.size() == 0 && hasMainType(type); + return m_types.mixinHighlightingTypes.size() == 0 && hasMainType(type); } bool HighlightingMark::hasFunctionArguments() const { - return originalCursor.argumentCount() > 0; + return m_originalCursor.argumentCount() > 0; } HighlightingMark::operator HighlightingMarkContainer() const { - return HighlightingMarkContainer(line, column, length, types); + return HighlightingMarkContainer(m_line, m_column, m_length, m_types); } namespace { @@ -133,9 +133,9 @@ void HighlightingMark::memberReferenceKind(const Cursor &cursor) { if (cursor.isDynamicCall()) { if (isFinalFunction(cursor) || isFunctionInFinalClass(cursor)) - types.mainHighlightingType = HighlightingType::Function; + m_types.mainHighlightingType = HighlightingType::Function; else - types.mainHighlightingType = HighlightingType::VirtualFunction; + m_types.mainHighlightingType = HighlightingType::VirtualFunction; } else { identifierKind(cursor.referenced(), Recursion::RecursivePass); } @@ -152,47 +152,47 @@ void HighlightingMark::referencedTypeKind(const Cursor &cursor) case CXCursor_TypedefDecl: case CXCursor_TemplateTypeParameter: case CXCursor_TypeAliasDecl: - case CXCursor_EnumDecl: types.mainHighlightingType = HighlightingType::Type; break; - default: types.mainHighlightingType = HighlightingType::Invalid; break; + case CXCursor_EnumDecl: m_types.mainHighlightingType = HighlightingType::Type; break; + default: m_types.mainHighlightingType = HighlightingType::Invalid; break; } } void HighlightingMark::overloadedDeclRefKind(const Cursor &cursor) { - types.mainHighlightingType = HighlightingType::Function; + m_types.mainHighlightingType = HighlightingType::Function; // CLANG-UPGRADE-CHECK: Workaround still needed? // Workaround https://bugs.llvm.org//show_bug.cgi?id=33256 - SomeType in // "using N::SomeType" is mistakenly considered as a CXCursor_OverloadedDeclRef. if (cursor.overloadedDeclarationsCount() >= 1 && cursor.overloadedDeclaration(0).kind() != CXCursor_FunctionDecl) { - types.mainHighlightingType = HighlightingType::Type; + m_types.mainHighlightingType = HighlightingType::Type; } } void HighlightingMark::variableKind(const Cursor &cursor) { if (cursor.isLocalVariable()) - types.mainHighlightingType = HighlightingType::LocalVariable; + m_types.mainHighlightingType = HighlightingType::LocalVariable; else - types.mainHighlightingType = HighlightingType::GlobalVariable; + m_types.mainHighlightingType = HighlightingType::GlobalVariable; if (isOutputArgument()) - types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument); + m_types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument); } void HighlightingMark::fieldKind(const Cursor &) { - types.mainHighlightingType = HighlightingType::Field; + m_types.mainHighlightingType = HighlightingType::Field; if (isOutputArgument()) - types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument); + m_types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument); } bool HighlightingMark::isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const { return cursor.isVirtualMethod() - && (originalCursor.isDeclaration() || originalCursor.isDefinition()); + && (m_originalCursor.isDeclaration() || m_originalCursor.isDefinition()); } namespace { bool isNotFinalFunction(const Cursor &cursor) @@ -203,37 +203,37 @@ bool isNotFinalFunction(const Cursor &cursor) } bool HighlightingMark::isRealDynamicCall(const Cursor &cursor) const { - return originalCursor.isDynamicCall() && isNotFinalFunction(cursor); + return m_originalCursor.isDynamicCall() && isNotFinalFunction(cursor); } void HighlightingMark::addExtraTypeIfFirstPass(HighlightingType type, Recursion recursion) { if (recursion == Recursion::FirstPass) - types.mixinHighlightingTypes.push_back(type); + m_types.mixinHighlightingTypes.push_back(type); } bool HighlightingMark::isArgumentInCurrentOutputArgumentLocations() const { - auto originalSourceLocation = originalCursor.cxSourceLocation(); + auto originalSourceLocation = m_originalCursor.cxSourceLocation(); const auto isNotSameOutputArgument = [&] (const CXSourceRange ¤tSourceRange) { return originalSourceLocation.int_data >= currentSourceRange.begin_int_data && originalSourceLocation.int_data <= currentSourceRange.end_int_data; }; - auto found = std::find_if(currentOutputArgumentRanges->begin(), - currentOutputArgumentRanges->end(), - isNotSameOutputArgument); + auto found = std::find_if(m_currentOutputArgumentRanges->begin(), + m_currentOutputArgumentRanges->end(), + isNotSameOutputArgument); - bool isOutputArgument = found != currentOutputArgumentRanges->end(); + bool isOutputArgument = found != m_currentOutputArgumentRanges->end(); return isOutputArgument; } bool HighlightingMark::isOutputArgument() const { - if (currentOutputArgumentRanges->empty()) + if (m_currentOutputArgumentRanges->empty()) return false; return isArgumentInCurrentOutputArgumentLocations(); @@ -241,7 +241,7 @@ bool HighlightingMark::isOutputArgument() const void HighlightingMark::collectOutputArguments(const Cursor &cursor) { - cursor.collectOutputArgumentRangesTo(*currentOutputArgumentRanges); + cursor.collectOutputArgumentRangesTo(*m_currentOutputArgumentRanges); filterOutPreviousOutputArguments(); } @@ -262,22 +262,22 @@ uint getStart(CXSourceRange cxSourceRange) void HighlightingMark::filterOutPreviousOutputArguments() { auto isAfterLocation = [this] (CXSourceRange outputRange) { - return getStart(outputRange) > offset; + return getStart(outputRange) > m_offset; }; - auto precedingBegin = std::partition(currentOutputArgumentRanges->begin(), - currentOutputArgumentRanges->end(), + auto precedingBegin = std::partition(m_currentOutputArgumentRanges->begin(), + m_currentOutputArgumentRanges->end(), isAfterLocation); - currentOutputArgumentRanges->erase(precedingBegin, currentOutputArgumentRanges->end()); + m_currentOutputArgumentRanges->erase(precedingBegin, m_currentOutputArgumentRanges->end()); } void HighlightingMark::functionKind(const Cursor &cursor, Recursion recursion) { if (isRealDynamicCall(cursor) || isVirtualMethodDeclarationOrDefinition(cursor)) - types.mainHighlightingType = HighlightingType::VirtualFunction; + m_types.mainHighlightingType = HighlightingType::VirtualFunction; else - types.mainHighlightingType = HighlightingType::Function; + m_types.mainHighlightingType = HighlightingType::Function; addExtraTypeIfFirstPass(HighlightingType::Declaration, recursion); } @@ -291,7 +291,7 @@ void HighlightingMark::identifierKind(const Cursor &cursor, Recursion recursion) case CXCursor_CallExpr: case CXCursor_CXXMethod: functionKind(cursor, recursion); break; case CXCursor_NonTypeTemplateParameter: - case CXCursor_CompoundStmt: types.mainHighlightingType = HighlightingType::LocalVariable; break; + case CXCursor_CompoundStmt: m_types.mainHighlightingType = HighlightingType::LocalVariable; break; case CXCursor_ParmDecl: case CXCursor_VarDecl: variableKind(cursor); break; case CXCursor_DeclRefExpr: identifierKind(cursor.referenced(), Recursion::RecursivePass); break; @@ -303,7 +303,7 @@ void HighlightingMark::identifierKind(const Cursor &cursor, Recursion recursion) case CXCursor_ObjCClassMethodDecl: case CXCursor_ObjCInstanceMethodDecl: case CXCursor_ObjCSynthesizeDecl: - case CXCursor_ObjCDynamicDecl: types.mainHighlightingType = HighlightingType::Field; break; + case CXCursor_ObjCDynamicDecl: m_types.mainHighlightingType = HighlightingType::Field; break; case CXCursor_TypeRef: referencedTypeKind(cursor); break; case CXCursor_ClassDecl: case CXCursor_ClassTemplatePartialSpecialization: @@ -328,16 +328,16 @@ void HighlightingMark::identifierKind(const Cursor &cursor, Recursion recursion) case CXCursor_ObjCProtocolDecl: case CXCursor_ObjCProtocolRef: case CXCursor_ObjCClassRef: - case CXCursor_ObjCSuperClassRef: types.mainHighlightingType = HighlightingType::Type; break; + case CXCursor_ObjCSuperClassRef: m_types.mainHighlightingType = HighlightingType::Type; break; case CXCursor_OverloadedDeclRef: overloadedDeclRefKind(cursor); break; - case CXCursor_FunctionTemplate: types.mainHighlightingType = HighlightingType::Function; break; - case CXCursor_EnumConstantDecl: types.mainHighlightingType = HighlightingType::Enumeration; break; - case CXCursor_PreprocessingDirective: types.mainHighlightingType = HighlightingType::Preprocessor; break; - case CXCursor_MacroExpansion: types.mainHighlightingType = HighlightingType::PreprocessorExpansion; break; - case CXCursor_MacroDefinition: types.mainHighlightingType = HighlightingType::PreprocessorDefinition; break; - case CXCursor_InclusionDirective: types.mainHighlightingType = HighlightingType::StringLiteral; break; + case CXCursor_FunctionTemplate: m_types.mainHighlightingType = HighlightingType::Function; break; + case CXCursor_EnumConstantDecl: m_types.mainHighlightingType = HighlightingType::Enumeration; break; + case CXCursor_PreprocessingDirective: m_types.mainHighlightingType = HighlightingType::Preprocessor; break; + case CXCursor_MacroExpansion: m_types.mainHighlightingType = HighlightingType::PreprocessorExpansion; break; + case CXCursor_MacroDefinition: m_types.mainHighlightingType = HighlightingType::PreprocessorDefinition; break; + case CXCursor_InclusionDirective: m_types.mainHighlightingType = HighlightingType::StringLiteral; break; case CXCursor_LabelRef: - case CXCursor_LabelStmt: types.mainHighlightingType = HighlightingType::Label; break; + case CXCursor_LabelStmt: m_types.mainHighlightingType = HighlightingType::Label; break; default: break; } } @@ -422,23 +422,23 @@ void HighlightingMark::collectKinds(CXTranslationUnit cxTranslationUnit, { auto cxTokenKind = clang_getTokenKind(*cxToken); - types = HighlightingTypes(); + m_types = HighlightingTypes(); switch (cxTokenKind) { - case CXToken_Keyword: types.mainHighlightingType = highlightingTypeForKeyword(cxTranslationUnit, cxToken, originalCursor); break; - case CXToken_Punctuation: types.mainHighlightingType = punctuationKind(cursor); break; + case CXToken_Keyword: m_types.mainHighlightingType = highlightingTypeForKeyword(cxTranslationUnit, cxToken, m_originalCursor); break; + case CXToken_Punctuation: m_types.mainHighlightingType = punctuationKind(cursor); break; case CXToken_Identifier: identifierKind(cursor, Recursion::FirstPass); break; - case CXToken_Comment: types.mainHighlightingType = HighlightingType::Comment; break; - case CXToken_Literal: types.mainHighlightingType = literalKind(cursor); break; + case CXToken_Comment: m_types.mainHighlightingType = HighlightingType::Comment; break; + case CXToken_Literal: m_types.mainHighlightingType = literalKind(cursor); break; } } std::ostream &operator<<(std::ostream &os, const HighlightingMark& highlightingMark) { - os << "(type: " << highlightingMark.types << ", " - << " line: " << highlightingMark.line << ", " - << " column: " << highlightingMark.column << ", " - << " length: " << highlightingMark.length + os << "(type: " << highlightingMark.m_types << ", " + << " line: " << highlightingMark.m_line << ", " + << " column: " << highlightingMark.m_column << ", " + << " length: " << highlightingMark.m_length << ")"; return os; diff --git a/src/tools/clangbackend/ipcsource/highlightingmark.h b/src/tools/clangbackend/ipcsource/highlightingmark.h index 9d3f2f8feee..a749a5c9223 100644 --- a/src/tools/clangbackend/ipcsource/highlightingmark.h +++ b/src/tools/clangbackend/ipcsource/highlightingmark.h @@ -47,9 +47,9 @@ public: HighlightingMark(const CXCursor &cxCursor, CXToken *cxToken, CXTranslationUnit cxTranslationUnit, - std::vector ¤tOutputArgumentRanges); - HighlightingMark(uint line, uint column, uint length, HighlightingTypes types); - HighlightingMark(uint line, uint column, uint length, HighlightingType type); + std::vector &m_currentOutputArgumentRanges); + HighlightingMark(uint m_line, uint m_column, uint m_length, HighlightingTypes m_types); + HighlightingMark(uint m_line, uint m_column, uint m_length, HighlightingType type); bool hasInvalidMainType() const; bool hasMainType(HighlightingType type) const; @@ -80,22 +80,22 @@ private: friend std::ostream &operator<<(std::ostream &os, const HighlightingMark& highlightingMark); private: - std::vector *currentOutputArgumentRanges = nullptr; - Cursor originalCursor; - uint line; - uint column; - uint length; - uint offset = 0; - HighlightingTypes types; + std::vector *m_currentOutputArgumentRanges = nullptr; + Cursor m_originalCursor; + uint m_line; + uint m_column; + uint m_length; + uint m_offset = 0; + HighlightingTypes m_types; }; inline bool operator==(const HighlightingMark &first, const HighlightingMark &second) { - return first.line == second.line - && first.column == second.column - && first.length == second.length - && first.types == second.types; + return first.m_line == second.m_line + && first.m_column == second.m_column + && first.m_length == second.m_length + && first.m_types == second.m_types; } } // namespace ClangBackEnd From e97ff9f739b61305161ebee524abbfb7972d33f1 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 24 Jul 2017 14:15:13 +0200 Subject: [PATCH 21/37] Clang: Do not warn about unhandled enum values ... in switch as long as there is a default case. Change-Id: I584660cb26ee03a9ce3e41b297af0093dce59d1f Reviewed-by: Nikolai Kosjar --- src/plugins/cpptools/clangdiagnosticconfigsmodel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/cpptools/clangdiagnosticconfigsmodel.cpp b/src/plugins/cpptools/clangdiagnosticconfigsmodel.cpp index 972f82c2d00..44187b6a102 100644 --- a/src/plugins/cpptools/clangdiagnosticconfigsmodel.cpp +++ b/src/plugins/cpptools/clangdiagnosticconfigsmodel.cpp @@ -83,6 +83,7 @@ static void addConfigForAlmostEveryWarning(ClangDiagnosticConfigsModel &model) QStringLiteral("-Wno-gnu-zero-variadic-macro-arguments"), QStringLiteral("-Wno-documentation"), QStringLiteral("-Wno-shadow"), + QStringLiteral("-Wno-switch-enum"), QStringLiteral("-Wno-missing-prototypes"), // Not optimal for C projects. QStringLiteral("-Wno-used-but-marked-unused"), // e.g. QTest::qWait } + commonWarnings()); From 99af4ae8e69db2e494cc8192b0b489c681456d91 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 20 Jul 2017 17:59:35 +0200 Subject: [PATCH 22/37] Clang: Show all tokens of a getter as output argument f(x.get()); -> x.get() should be shown as a output argument Task-number: QTCREATORBUG-18591 Change-Id: I99f5637660bcd0a889338ebfa6737d79de226f87 Reviewed-by: Nikolai Kosjar Reviewed-by: Marco Bubke --- .../ipcsource/highlightingmark.cpp | 18 ++++++++----- .../ipcsource/highlightingmarks.cpp | 12 +++++++++ .../ipcsource/highlightingmarks.h | 2 ++ .../unit/unittest/data/highlightingmarks.cpp | 14 ++++++++++ .../unit/unittest/highlightingmarks-test.cpp | 27 +++++++++++++++++++ 5 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/tools/clangbackend/ipcsource/highlightingmark.cpp b/src/tools/clangbackend/ipcsource/highlightingmark.cpp index 03dd894a694..bc918326a7c 100644 --- a/src/tools/clangbackend/ipcsource/highlightingmark.cpp +++ b/src/tools/clangbackend/ipcsource/highlightingmark.cpp @@ -247,22 +247,22 @@ void HighlightingMark::collectOutputArguments(const Cursor &cursor) namespace { -uint getStart(CXSourceRange cxSourceRange) +uint getEnd(CXSourceRange cxSourceRange) { - CXSourceLocation startSourceLocation = clang_getRangeStart(cxSourceRange); + CXSourceLocation startSourceLocation = clang_getRangeEnd(cxSourceRange); - uint startOffset; + uint endOffset; - clang_getFileLocation(startSourceLocation, nullptr, nullptr, nullptr, &startOffset); + clang_getFileLocation(startSourceLocation, nullptr, nullptr, nullptr, &endOffset); - return startOffset; + return endOffset; } } void HighlightingMark::filterOutPreviousOutputArguments() { auto isAfterLocation = [this] (CXSourceRange outputRange) { - return getStart(outputRange) > m_offset; + return getEnd(outputRange) > m_offset; }; auto precedingBegin = std::partition(m_currentOutputArgumentRanges->begin(), @@ -279,6 +279,9 @@ void HighlightingMark::functionKind(const Cursor &cursor, Recursion recursion) else m_types.mainHighlightingType = HighlightingType::Function; + if (isOutputArgument()) + m_types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument); + addExtraTypeIfFirstPass(HighlightingType::Declaration, recursion); } @@ -384,6 +387,9 @@ HighlightingType HighlightingMark::punctuationKind(const Cursor &cursor) default: break; } + if (isOutputArgument()) + m_types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument); + return highlightingType; } diff --git a/src/tools/clangbackend/ipcsource/highlightingmarks.cpp b/src/tools/clangbackend/ipcsource/highlightingmarks.cpp index 725e6eb3169..2e157ff835e 100644 --- a/src/tools/clangbackend/ipcsource/highlightingmarks.cpp +++ b/src/tools/clangbackend/ipcsource/highlightingmarks.cpp @@ -109,4 +109,16 @@ HighlightingMark HighlightingMarks::operator[](size_t index) const currentOutputArgumentRanges); } +std::ostream &operator<<(std::ostream &out, const HighlightingMarks &marks) +{ + out << "["; + + for (const HighlightingMark entry : marks) + out << entry; + + out << "]"; + + return out; +} + } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/highlightingmarks.h b/src/tools/clangbackend/ipcsource/highlightingmarks.h index 6904bb31847..e573dc267e4 100644 --- a/src/tools/clangbackend/ipcsource/highlightingmarks.h +++ b/src/tools/clangbackend/ipcsource/highlightingmarks.h @@ -69,4 +69,6 @@ private: std::vector cxCursor; }; +std::ostream &operator<<(std::ostream &out, const HighlightingMarks &marks); + } // namespace ClangBackEnd diff --git a/tests/unit/unittest/data/highlightingmarks.cpp b/tests/unit/unittest/data/highlightingmarks.cpp index 7c78ddf1965..5b3374d582a 100644 --- a/tests/unit/unittest/data/highlightingmarks.cpp +++ b/tests/unit/unittest/data/highlightingmarks.cpp @@ -565,3 +565,17 @@ void g(OtherOperator o, int var) { o(var); } + +void NonConstPointerArgument(int &argument); + +struct PointerGetterClass +{ + int &getter(); +}; + +void f32() +{ + PointerGetterClass x; + + NonConstPointerArgument(x.getter()); +} diff --git a/tests/unit/unittest/highlightingmarks-test.cpp b/tests/unit/unittest/highlightingmarks-test.cpp index c22c3e2df88..8592bb67be4 100644 --- a/tests/unit/unittest/highlightingmarks-test.cpp +++ b/tests/unit/unittest/highlightingmarks-test.cpp @@ -60,6 +60,8 @@ using testing::IsNull; using testing::NotNull; using testing::Gt; using testing::Contains; +using testing::ElementsAre; +using testing::_; using testing::EndsWith; using testing::AllOf; using testing::Not; @@ -96,6 +98,14 @@ MATCHER_P2(HasTwoTypes, firstType, secondType, return arg.hasMainType(firstType) && arg.hasMixinType(secondType); } +MATCHER_P(HasMixin, firstType, + std::string(negation ? "isn't " : "is ") + + PrintToString(firstType) + ) +{ + return arg.hasMixinType(firstType); +} + struct Data { Data() { @@ -1021,6 +1031,23 @@ TEST_F(HighlightingMarks, ConstPointerArgument) HasOnlyType(HighlightingType::LocalVariable)); } +TEST_F(HighlightingMarks, NonConstPointerGetterAsArgument) +{ + const auto infos = translationUnit.highlightingMarksInRange(sourceRange(580, 41)); + + ASSERT_THAT(infos, + ElementsAre(_, + _, + HasMixin(HighlightingType::OutputArgument), + HasMixin(HighlightingType::OutputArgument), + HasMixin(HighlightingType::OutputArgument), + HasMixin(HighlightingType::OutputArgument), + HasMixin(HighlightingType::OutputArgument), + _, + _, + _)); +} + TEST_F(HighlightingMarks, NonConstReferenceArgumentCallInsideCall) { const auto infos = translationUnit.highlightingMarksInRange(sourceRange(501, 64)); From 948fad02d11ba422e180f4f15faf068eb4e69b9d Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Sun, 23 Jul 2017 08:01:41 +0300 Subject: [PATCH 23/37] Git: Recurse into submodules on grep if applicable (Git >= 2.13) Change-Id: I5028d6a46749b22cc0e0f5707c9e283126511902 Reviewed-by: Tobias Hunger --- src/plugins/git/gitgrep.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index 9e09c7a90a5..59b1fb95663 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -144,7 +144,8 @@ public: GitClient *client = GitPlugin::client(); QStringList arguments = { "-c", "color.grep.match=bold red", - "grep", "-zn", "--no-full-name", "--color=always" + "-c", "color.grep=always", + "grep", "-zn", "--no-full-name" }; if (!(m_parameters.flags & FindCaseSensitively)) arguments << "-i"; @@ -154,6 +155,8 @@ public: arguments << "-P"; else arguments << "-F"; + if (client->gitVersion() >= 0x021300) + arguments << "--recurse-submodules"; arguments << "-e" << m_parameters.text; GitGrepParameters params = m_parameters.searchEngineParameters.value(); if (!params.ref.isEmpty()) { From 257bf341caf4a7d79da1b2cf8440bca772c0eeb9 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Sun, 23 Jul 2017 09:13:26 +0300 Subject: [PATCH 24/37] GccToolchain: Minor cleanup Change-Id: I9bf2d935bf95ff45b29ebfbefd8f8aaf8e22e3ac Reviewed-by: Tobias Hunger --- src/plugins/projectexplorer/gcctoolchain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index 1c058a42a92..cfe0ca314cb 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -431,7 +431,7 @@ static Utils::FileName findLocalCompiler(const Utils::FileName &compilerPath, && !pathEntry.contains("distcc"); }); - QTC_ASSERT(path != FileName(), return compilerPath); + QTC_ASSERT(!path.isEmpty(), return compilerPath); return path; } From 15e6ec455259d0912d7dd83ecdae15482152745e Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 24 Jul 2017 11:20:25 +0200 Subject: [PATCH 25/37] Utils: Make the wizard icon for files wider In order to able to fit some overlay text to it. (See following commits). Change-Id: I9b762b20d9a17e5bf779bf1d197804803fa812ad Reviewed-by: Tim Jenssen Reviewed-by: Alessandro Portale --- src/libs/utils/images/wizardicon-file.png | Bin 214 -> 214 bytes src/libs/utils/images/wizardicon-file@2x.png | Bin 255 -> 258 bytes src/tools/icons/qtcreatoricons.svg | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/images/wizardicon-file.png b/src/libs/utils/images/wizardicon-file.png index fd3f5bdd347229db2b7d3d08908cc17793872f1d..01df96631937af6c53ce65e9633dee896dfb376d 100644 GIT binary patch delta 108 zcmcb{c#UyFVXFVz(+7DQ6a-uX-<*ibIT+T%7m}nOHHCdrs>F>O2mZZ2?SC?#v2-0@ zg7S&=Uqzy<4(zpd@aEsbvBhoyk~CG4VZIMtJIf) Pfq}u()z4*}Q$iB}GqEge delta 108 zcmcb{c#UyFVQO!3f&#loiGqWXUS}9`Wy<;=^GnuDhnZ`{91_lOC LS3j3^P6 Date: Fri, 21 Jul 2017 16:43:03 +0200 Subject: [PATCH 26/37] Core: Enable text overlay for "New File/Project" icons Change-Id: I6f206b2c97f7435b4de3a06c32b3933f3519181a Reviewed-by: Tobias Hunger --- src/plugins/coreplugin/dialogs/newdialog.cpp | 22 ++++++++++++++++++- src/plugins/coreplugin/iwizardfactory.h | 3 +++ .../jsonwizard/jsonwizardfactory.cpp | 5 +++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/dialogs/newdialog.cpp b/src/plugins/coreplugin/dialogs/newdialog.cpp index 66e794b2e48..6ffb1e89b7d 100644 --- a/src/plugins/coreplugin/dialogs/newdialog.cpp +++ b/src/plugins/coreplugin/dialogs/newdialog.cpp @@ -369,6 +369,26 @@ IWizardFactory *NewDialog::currentWizardFactory() const return factoryOfItem(m_model->itemFromIndex(index)); } +static QIcon iconWithText(const QIcon &icon, const QString &text) +{ + if (text.isEmpty()) + return icon; + QIcon iconWithText; + for (const QSize &pixmapSize : icon.availableSizes()) { + QPixmap pixmap = icon.pixmap(pixmapSize); + QFont font; + font.setPixelSize(qMin(pixmap.height(), pixmap.width()) / 5); + QPainter p(&pixmap); + p.setPen(qRgb(0x6b, 0x70, 0x80)); + p.setFont(font); + QTextOption textOption(Qt::AlignHCenter | Qt::AlignBottom); + textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + p.drawText(pixmap.rect().adjusted(9, 10, -9, -10), text, textOption); + iconWithText.addPixmap(pixmap); + } + return iconWithText; +} + void NewDialog::addItem(QStandardItem *topLevelCategoryItem, IWizardFactory *factory) { const QString categoryName = factory->category(); @@ -394,7 +414,7 @@ void NewDialog::addItem(QStandardItem *topLevelCategoryItem, IWizardFactory *fac wizardIcon = m_dummyIcon; else wizardIcon = factory->icon(); - wizardItem->setIcon(wizardIcon); + wizardItem->setIcon(iconWithText(wizardIcon, factory->iconText())); wizardItem->setData(QVariant::fromValue(WizardFactoryContainer(factory, 0)), Qt::UserRole); wizardItem->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); categoryItem->appendRow(wizardItem); diff --git a/src/plugins/coreplugin/iwizardfactory.h b/src/plugins/coreplugin/iwizardfactory.h index 30b6cb164a2..d1f218c1334 100644 --- a/src/plugins/coreplugin/iwizardfactory.h +++ b/src/plugins/coreplugin/iwizardfactory.h @@ -60,6 +60,7 @@ public: Id id() const { return m_id; } WizardKind kind() const { return m_supportedProjectTypes.isEmpty() ? FileWizard : ProjectWizard; } QIcon icon() const { return m_icon; } + QString iconText() const { return m_iconText; } QString description() const { return m_description; } QString displayName() const { return m_displayName; } QString category() const { return m_category; } @@ -72,6 +73,7 @@ public: void setId(const Id id) { m_id = id; } void setSupportedProjectTypes(const QSet &projectTypes) { m_supportedProjectTypes = projectTypes; } void setIcon(const QIcon &icon) { m_icon = icon; } + void setIconText(const QString &iconText) { m_iconText = iconText; } void setDescription(const QString &description) { m_description = description; } void setDisplayName(const QString &displayName) { m_displayName = displayName; } void setCategory(const QString &category) { m_category = category; } @@ -123,6 +125,7 @@ private: QAction *m_action = 0; QIcon m_icon; + QString m_iconText; QString m_description; QString m_displayName; QString m_category; diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp index 7856a08b28b..5faa25902da 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp @@ -70,6 +70,7 @@ static const char CATEGORY_KEY[] = "category"; static const char CATEGORY_NAME_KEY[] = "trDisplayCategory"; static const char DISPLAY_NAME_KEY[] = "trDisplayName"; static const char ICON_KEY[] = "icon"; +static const char ICON_TEXT_KEY[] = "iconText"; static const char IMAGE_KEY[] = "image"; static const char DESCRIPTION_KEY[] = "trDescription"; static const char REQUIRED_FEATURES_KEY[] = "featuresRequired"; @@ -559,6 +560,10 @@ bool JsonWizardFactory::initialize(const QVariantMap &data, const QDir &baseDir, setIcon(QIcon(strVal)); } + strVal = data.value(QLatin1String(ICON_TEXT_KEY)).toString(); + if (!strVal.isEmpty()) + setIconText(strVal); + strVal = data.value(QLatin1String(IMAGE_KEY)).toString(); if (!strVal.isEmpty()) { strVal = baseDir.absoluteFilePath(strVal); From 9113125a5e3ee4e1032fc7d2621612531ed0663c Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 21 Jul 2017 16:44:38 +0200 Subject: [PATCH 27/37] Wizards: Add file extension as text overlay to some wizards Change-Id: Ibfd1144271c4381c7125db80713cbde431a54cf7 Reviewed-by: Alessandro Portale --- share/qtcreator/templates/wizards/classes/cpp/wizard.json | 1 + share/qtcreator/templates/wizards/classes/python/wizard.json | 1 + share/qtcreator/templates/wizards/classes/qtquickui/wizard.json | 1 + share/qtcreator/templates/wizards/files/cppheader/wizard.json | 1 + share/qtcreator/templates/wizards/files/cppsource/wizard.json | 1 + share/qtcreator/templates/wizards/files/form/wizard.json | 1 + .../templates/wizards/files/glsl/gl/fragment/wizard.json | 1 + .../qtcreator/templates/wizards/files/glsl/gl/vertex/wizard.json | 1 + .../templates/wizards/files/glsl/gles/fragment/wizard.json | 1 + .../templates/wizards/files/glsl/gles/vertex/wizard.json | 1 + share/qtcreator/templates/wizards/files/java/wizard.json | 1 + share/qtcreator/templates/wizards/files/js/wizard.json | 1 + share/qtcreator/templates/wizards/files/modeling/wizard.json | 1 + share/qtcreator/templates/wizards/files/python/wizard.json | 1 + share/qtcreator/templates/wizards/files/qrc/wizard.json | 1 + share/qtcreator/templates/wizards/files/qtquick2/wizard.json | 1 + share/qtcreator/templates/wizards/files/scxml/wizard.json | 1 + share/qtcreator/templates/wizards/files/text/wizard.json | 1 + src/plugins/designer/formeditorplugin.cpp | 1 + 19 files changed, 19 insertions(+) diff --git a/share/qtcreator/templates/wizards/classes/cpp/wizard.json b/share/qtcreator/templates/wizards/classes/cpp/wizard.json index 7c690b54c6f..18b84d8d56c 100644 --- a/share/qtcreator/templates/wizards/classes/cpp/wizard.json +++ b/share/qtcreator/templates/wizards/classes/cpp/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates a C++ header and a source file for a new class that you can add to a C++ project.", "trDisplayName": "C++ Class", "trDisplayCategory": "C++", + "iconText": "h/cpp", "enabled": "%{JS: [ %{Plugins} ].indexOf('CppEditor') >= 0}", "options": diff --git a/share/qtcreator/templates/wizards/classes/python/wizard.json b/share/qtcreator/templates/wizards/classes/python/wizard.json index d3613085b09..7031d0ba991 100644 --- a/share/qtcreator/templates/wizards/classes/python/wizard.json +++ b/share/qtcreator/templates/wizards/classes/python/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates new Python class file.", "trDisplayName": "Python Class", "trDisplayCategory": "Python", + "iconText": "py", "enabled": "%{JS: [ %{Plugins} ].indexOf('PythonEditor') >= 0}", "options": diff --git a/share/qtcreator/templates/wizards/classes/qtquickui/wizard.json b/share/qtcreator/templates/wizards/classes/qtquickui/wizard.json index 3786457ee10..a1d43389940 100644 --- a/share/qtcreator/templates/wizards/classes/qtquickui/wizard.json +++ b/share/qtcreator/templates/wizards/classes/qtquickui/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates a Qt Quick Designer UI form along with a matching QML file for implementation purposes. You can add the form and file to an existing Qt Quick Project.", "trDisplayName": "QtQuick UI File", "trDisplayCategory": "Qt", + "iconText": "ui.qml", "featuresRequired": [ "QtSupport.Wizards.FeatureQtQuick.UiFiles" ], "enabled": "%{JS: [ %{Plugins} ].indexOf('QmlJSEditor') >= 0}", diff --git a/share/qtcreator/templates/wizards/files/cppheader/wizard.json b/share/qtcreator/templates/wizards/files/cppheader/wizard.json index 6ea6fe5b09a..bda6770d098 100644 --- a/share/qtcreator/templates/wizards/files/cppheader/wizard.json +++ b/share/qtcreator/templates/wizards/files/cppheader/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates a C++ header file that you can add to a C++ project.", "trDisplayName": "C++ Header File", "trDisplayCategory": "C++", + "iconText": "h", "enabled": "%{JS: [ %{Plugins} ].indexOf('CppEditor') >= 0}", "options": { "key": "FileName", "value": "%{JS: Cpp.fileName('%{TargetPath}', '%{JS: Util.preferredSuffix('text/x-c++hdr')}')}" }, diff --git a/share/qtcreator/templates/wizards/files/cppsource/wizard.json b/share/qtcreator/templates/wizards/files/cppsource/wizard.json index 504de97238e..7eebc282b50 100644 --- a/share/qtcreator/templates/wizards/files/cppsource/wizard.json +++ b/share/qtcreator/templates/wizards/files/cppsource/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates a C++ source file that you can add to a C++ project.", "trDisplayName": "C++ Source File", "trDisplayCategory": "C++", + "iconText": "cpp", "enabled": "%{JS: [ %{Plugins} ].indexOf('CppEditor') >= 0}", "options": { "key": "FileName", "value": "%{JS: Cpp.fileName('%{TargetPath}', '%{JS: Util.preferredSuffix('text/x-c++src')}')}" }, diff --git a/share/qtcreator/templates/wizards/files/form/wizard.json b/share/qtcreator/templates/wizards/files/form/wizard.json index 2e3a42671d5..26d15d2b59a 100644 --- a/share/qtcreator/templates/wizards/files/form/wizard.json +++ b/share/qtcreator/templates/wizards/files/form/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates a Qt Designer form that you can add to a Qt Widget Project. This is useful if you already have an existing class for the UI business logic.", "trDisplayName": "Qt Designer Form", "trDisplayCategory": "Qt", + "iconText": "ui", "enabled": "%{JS: [ %{Plugins} ].indexOf('Designer') >= 0}", "options": [ diff --git a/share/qtcreator/templates/wizards/files/glsl/gl/fragment/wizard.json b/share/qtcreator/templates/wizards/files/glsl/gl/fragment/wizard.json index e3229e274c5..eb5e9947826 100644 --- a/share/qtcreator/templates/wizards/files/glsl/gl/fragment/wizard.json +++ b/share/qtcreator/templates/wizards/files/glsl/gl/fragment/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates a fragment shader in the Desktop OpenGL Shading Language (GLSL). Fragment shaders generate the final pixel colors for triangles, points and lines rendered with OpenGL.", "trDisplayName": "Fragment Shader (Desktop OpenGL)", "trDisplayCategory": "GLSL", + "iconText": "frag", "platformIndependent": true, "enabled": "%{JS: [ %{Plugins} ].indexOf('GLSLEditor') >= 0}", diff --git a/share/qtcreator/templates/wizards/files/glsl/gl/vertex/wizard.json b/share/qtcreator/templates/wizards/files/glsl/gl/vertex/wizard.json index a1c5904e4c9..bd76a76d6b6 100644 --- a/share/qtcreator/templates/wizards/files/glsl/gl/vertex/wizard.json +++ b/share/qtcreator/templates/wizards/files/glsl/gl/vertex/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates a vertex shader in the Desktop OpenGL Shading Language (GLSL). Vertex shaders transform the positions, normals and texture coordinates of triangles, points and lines rendered with OpenGL.", "trDisplayName": "Vertex Shader (Desktop OpenGL)", "trDisplayCategory": "GLSL", + "iconText": "vert", "platformIndependent": true, "enabled": "%{JS: [ %{Plugins} ].indexOf('GLSLEditor') >= 0}", diff --git a/share/qtcreator/templates/wizards/files/glsl/gles/fragment/wizard.json b/share/qtcreator/templates/wizards/files/glsl/gles/fragment/wizard.json index c83c58e8bbb..c95b336aea6 100644 --- a/share/qtcreator/templates/wizards/files/glsl/gles/fragment/wizard.json +++ b/share/qtcreator/templates/wizards/files/glsl/gles/fragment/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates a fragment shader in the OpenGL/ES 2.0 Shading Language (GLSL/ES). Fragment shaders generate the final pixel colors for triangles, points and lines rendered with OpenGL.", "trDisplayName": "Fragment Shader (OpenGL/ES 2.0)", "trDisplayCategory": "GLSL", + "iconText": "fsh", "platformIndependent": true, "enabled": "%{JS: [ %{Plugins} ].indexOf('GLSLEditor') >= 0}", diff --git a/share/qtcreator/templates/wizards/files/glsl/gles/vertex/wizard.json b/share/qtcreator/templates/wizards/files/glsl/gles/vertex/wizard.json index edddc2dc157..68d430d29dd 100644 --- a/share/qtcreator/templates/wizards/files/glsl/gles/vertex/wizard.json +++ b/share/qtcreator/templates/wizards/files/glsl/gles/vertex/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates a vertex shader in the OpenGL/ES 2.0 Shading Language (GLSL/ES). Vertex shaders transform the positions, normals and texture coordinates of triangles, points and lines rendered with OpenGL.", "trDisplayName": "Vertex Shader (OpenGL/ES 2.0)", "trDisplayCategory": "GLSL", + "iconText": "vsh", "platformIndependent": true, "enabled": "%{JS: [ %{Plugins} ].indexOf('GLSLEditor') >= 0}", diff --git a/share/qtcreator/templates/wizards/files/java/wizard.json b/share/qtcreator/templates/wizards/files/java/wizard.json index 8986fb961b1..427dc84e16a 100644 --- a/share/qtcreator/templates/wizards/files/java/wizard.json +++ b/share/qtcreator/templates/wizards/files/java/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates a Java file with boilerplate code.", "trDisplayName": "Java File", "trDisplayCategory": "Java", + "iconText": "java", "enabled": "%{JS: [ %{Plugins} ].indexOf('Android') >= 0}", "options": [ { "key": "ClassName", "value": "%{JS: '%{FileName}'.charAt(0).toUpperCase() + '%{FileName}'.substr(1)}" } ], diff --git a/share/qtcreator/templates/wizards/files/js/wizard.json b/share/qtcreator/templates/wizards/files/js/wizard.json index 57886e007bc..62d3211cda3 100644 --- a/share/qtcreator/templates/wizards/files/js/wizard.json +++ b/share/qtcreator/templates/wizards/files/js/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates a JavaScript file.", "trDisplayName": "JS File", "trDisplayCategory": "Qt", + "iconText": "js", "enabled": "%{JS: [ %{Plugins} ].indexOf('QmlJSEditor') >= 0}", "pages" : diff --git a/share/qtcreator/templates/wizards/files/modeling/wizard.json b/share/qtcreator/templates/wizards/files/modeling/wizard.json index 75b0958524e..2f8cff689a1 100644 --- a/share/qtcreator/templates/wizards/files/modeling/wizard.json +++ b/share/qtcreator/templates/wizards/files/modeling/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates a new empty model with an empty diagram.", "trDisplayName": "Model", "trDisplayCategory": "Modeling", + "iconText": "qmodel", "platformIndependent": true, "enabled": "%{JS: [ %{Plugins} ].indexOf('ModelEditor') >= 0}", diff --git a/share/qtcreator/templates/wizards/files/python/wizard.json b/share/qtcreator/templates/wizards/files/python/wizard.json index d9bf8456317..32b720f3d40 100644 --- a/share/qtcreator/templates/wizards/files/python/wizard.json +++ b/share/qtcreator/templates/wizards/files/python/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates an empty Python script file using UTF-8 charset.", "trDisplayName": "Python File", "trDisplayCategory": "Python", + "iconText": "py", "enabled": "%{JS: [ %{Plugins} ].indexOf('PythonEditor') >= 0}", "pages" : diff --git a/share/qtcreator/templates/wizards/files/qrc/wizard.json b/share/qtcreator/templates/wizards/files/qrc/wizard.json index 0badcf7acc8..bbbd8e98f99 100644 --- a/share/qtcreator/templates/wizards/files/qrc/wizard.json +++ b/share/qtcreator/templates/wizards/files/qrc/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates a Qt Resource file (.qrc).", "trDisplayName": "Qt Resource File", "trDisplayCategory": "Qt", + "iconText": "qrc", "enabled": "%{JS: [ %{Plugins} ].indexOf('ResourceEditor') >= 0}", "pages" : diff --git a/share/qtcreator/templates/wizards/files/qtquick2/wizard.json b/share/qtcreator/templates/wizards/files/qtquick2/wizard.json index 5a4c8bbf6fd..544368b1735 100644 --- a/share/qtcreator/templates/wizards/files/qtquick2/wizard.json +++ b/share/qtcreator/templates/wizards/files/qtquick2/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates a QML file with boilerplate code, starting with \"import QtQuick 2.0\".", "trDisplayName": "QML File (Qt Quick 2)", "trDisplayCategory": "Qt", + "iconText": "qml", "enabled": "%{JS: [ %{Plugins} ].indexOf('QmlJSEditor') >= 0}", "pages" : diff --git a/share/qtcreator/templates/wizards/files/scxml/wizard.json b/share/qtcreator/templates/wizards/files/scxml/wizard.json index f9d72469252..893662337d8 100644 --- a/share/qtcreator/templates/wizards/files/scxml/wizard.json +++ b/share/qtcreator/templates/wizards/files/scxml/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates a new empty state chart.", "trDisplayName": "State Chart", "trDisplayCategory": "Modeling", + "iconText": "scxml", "platformIndependent": true, "enabled": "%{JS: [ %{Plugins} ].indexOf('QtSupport') >= 0}", diff --git a/share/qtcreator/templates/wizards/files/text/wizard.json b/share/qtcreator/templates/wizards/files/text/wizard.json index 2e20706c554..11e0577a2de 100644 --- a/share/qtcreator/templates/wizards/files/text/wizard.json +++ b/share/qtcreator/templates/wizards/files/text/wizard.json @@ -6,6 +6,7 @@ "trDescription": "Creates an empty file.", "trDisplayName": "Empty File", "trDisplayCategory": "General", + "iconText": "txt", "platformIndependent": true, "enabled": "%{JS: [ %{Plugins} ].indexOf('TextEditor') >= 0}", diff --git a/src/plugins/designer/formeditorplugin.cpp b/src/plugins/designer/formeditorplugin.cpp index 1abc12a8032..8a4f0af3de7 100644 --- a/src/plugins/designer/formeditorplugin.cpp +++ b/src/plugins/designer/formeditorplugin.cpp @@ -87,6 +87,7 @@ bool FormEditorPlugin::initialize(const QStringList &arguments, QString *error) wizard->setCategory(QLatin1String(Core::Constants::WIZARD_CATEGORY_QT)); wizard->setDisplayCategory(QCoreApplication::translate("Core", Core::Constants::WIZARD_TR_CATEGORY_QT)); wizard->setDisplayName(tr("Qt Designer Form Class")); + wizard->setIconText("ui/h"); wizard->setId("C.FormClass"); wizard->setDescription(tr("Creates a Qt Designer form along with a matching class (C++ header and source file) " "for implementation purposes. You can add the form and class to an existing Qt Widget Project.")); From 8ca2f9d3fa80b2757bf3c5cc2077742174174178 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Mon, 24 Jul 2017 17:10:29 +0200 Subject: [PATCH 28/37] Clang: Tests: Sort files in unittest.pro Change-Id: I5473230ba9bc1b6c1a9520971d66918d545c9e5b Reviewed-by: Marco Bubke --- tests/unit/unittest/unittest.pro | 124 +++++++++++++++---------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index fb83baa8d8e..be7632ecd53 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -36,38 +36,38 @@ QMAKE_SUBSTITUTES += cpptoolsjson DEFINES += CPPTOOLS_JSON=\"R\\\"xxx($${cpptoolsjson.output})xxx\\\"\" SOURCES += \ + changedfilepathcompressor-test.cpp \ + clangpathwatcher-test.cpp \ + clangqueryexamplehighlightmarker-test.cpp \ + clangqueryhighlightmarker-test.cpp \ clientserverinprocess-test.cpp \ - lineprefixer-test.cpp \ + clientserveroutsideprocess-test.cpp \ cppprojectfilecategorizer-test.cpp \ cppprojectinfogenerator-test.cpp \ cppprojectpartchooser-test.cpp \ - processevents-utilities.cpp \ + fakeprocess.cpp \ + faketimer.cpp \ + filepath-test.cpp \ + gtest-creator-printing.cpp \ + gtest-qt-printing.cpp \ + lineprefixer-test.cpp \ + matchingtext-test.cpp \ mimedatabase-utilities.cpp \ + pchgenerator-test.cpp \ + pchmanagerclientserverinprocess-test.cpp \ + pchmanagerclient-test.cpp \ + pchmanagerserver-test.cpp \ + processevents-utilities.cpp \ + projectparts-test.cpp \ + projectupdater-test.cpp \ readandwritemessageblock-test.cpp \ sizedarray-test.cpp \ smallstring-test.cpp \ + sourcerangefilter-test.cpp \ spydummy.cpp \ + stringcache-test.cpp \ unittests-main.cpp \ utf8-test.cpp \ - gtest-qt-printing.cpp \ - gtest-creator-printing.cpp \ - clientserveroutsideprocess-test.cpp \ - clangpathwatcher-test.cpp \ - projectparts-test.cpp \ - stringcache-test.cpp \ - changedfilepathcompressor-test.cpp \ - faketimer.cpp \ - pchgenerator-test.cpp \ - fakeprocess.cpp \ - pchmanagerclient-test.cpp \ - projectupdater-test.cpp \ - pchmanagerserver-test.cpp \ - pchmanagerclientserverinprocess-test.cpp \ - filepath-test.cpp \ - sourcerangefilter-test.cpp \ - clangqueryexamplehighlightmarker-test.cpp \ - clangqueryhighlightmarker-test.cpp \ - matchingtext-test.cpp !isEmpty(LIBCLANG_LIBS) { SOURCES += \ @@ -81,21 +81,25 @@ SOURCES += \ clangcompletioncontextanalyzer-test.cpp \ clangcreateinitialdocumentpreamblejob-test.cpp \ clangdiagnosticfilter-test.cpp \ + clangdocumentprocessors-test.cpp \ + clangdocumentprocessor-test.cpp \ clangdocuments-test.cpp \ clangdocument-test.cpp \ - clangdocumentprocessor-test.cpp \ - clangdocumentprocessors-test.cpp \ clangfixitoperation-test.cpp \ clangisdiagnosticrelatedtolocation-test.cpp \ clangjobqueue-test.cpp \ clangjobs-test.cpp \ + clangparsesupportivetranslationunitjob-test.cpp \ + clangreferencescollector-test.cpp \ + clangreparsesupportivetranslationunitjob-test.cpp \ clangrequestdocumentannotationsjob-test.cpp \ clangrequestreferencesjob-test.cpp \ - clangreferencescollector-test.cpp \ clangstring-test.cpp \ - clangtranslationunit-test.cpp \ + clangsupportivetranslationunitinitializer-test.cpp \ clangtranslationunits-test.cpp \ + clangtranslationunit-test.cpp \ clangupdatedocumentannotationsjob-test.cpp \ + codecompleter-test.cpp \ codecompletionsextractor-test.cpp \ completionchunkstotextconverter-test.cpp \ createtablesqlstatementbuilder-test.cpp \ @@ -120,28 +124,24 @@ SOURCES += \ unsavedfiles-test.cpp \ unsavedfile-test.cpp \ utf8positionfromlinecolumn-test.cpp \ - clangparsesupportivetranslationunitjob-test.cpp \ - clangreparsesupportivetranslationunitjob-test.cpp \ - clangsupportivetranslationunitinitializer-test.cpp \ - codecompleter-test.cpp } !isEmpty(LIBTOOLING_LIBS) { SOURCES += \ - clangquery-test.cpp \ clangquerygatherer-test.cpp \ clangqueryprojectfindfilter-test.cpp \ + clangquery-test.cpp \ + gtest-clang-printing.cpp \ + includecollector-test.cpp \ + pchcreator-test.cpp \ refactoringclientserverinprocess-test.cpp \ refactoringclient-test.cpp \ refactoringcompilationdatabase-test.cpp \ refactoringengine-test.cpp \ refactoringserver-test.cpp \ - symbolfinder-test.cpp \ sourcerangeextractor-test.cpp \ - gtest-clang-printing.cpp \ + symbolfinder-test.cpp \ testclangtool.cpp \ - includecollector-test.cpp \ - pchcreator-test.cpp } exists($$GOOGLEBENCHMARK_DIR) { @@ -150,53 +150,53 @@ SOURCES += \ } HEADERS += \ + compare-operators.h \ + conditionally-disabled-tests.h \ + dummyclangipcclient.h \ + dynamicastmatcherdiagnosticcontainer-matcher.h \ + fakeprocess.h \ + faketimer.h \ filesystem-utilities.h \ googletest.h \ - gtest-qt-printing.h \ - processevents-utilities.h \ - mimedatabase-utilities.h \ - spydummy.h \ - sourcerangecontainer-matcher.h \ - dynamicastmatcherdiagnosticcontainer-matcher.h \ - mocksearchresult.h \ - mocksearch.h \ - mocksearchhandle.h \ - compare-operators.h \ gtest-creator-printing.h \ - conditionally-disabled-tests.h \ - mockqfilesystemwatcher.h \ - mockclangpathwatcher.h \ - mockprojectparts.h \ - mockclangpathwatchernotifier.h \ + gtest-qt-printing.h \ + mimedatabase-utilities.h \ mockchangedfilepathcompressor.h \ - faketimer.h \ - mockpchgeneratornotifier.h \ - fakeprocess.h \ - mockpchmanagerserver.h \ - mockpchmanagerclient.h \ - testenvironment.h \ - mockpchmanagernotifier.h \ - mockpchcreator.h \ - dummyclangipcclient.h \ mockclangcodemodelclient.h \ mockclangcodemodelserver.h \ - mocksyntaxhighligher.h + mockclangpathwatcher.h \ + mockclangpathwatchernotifier.h \ + mockpchcreator.h \ + mockpchgeneratornotifier.h \ + mockpchmanagerclient.h \ + mockpchmanagernotifier.h \ + mockpchmanagerserver.h \ + mockprojectparts.h \ + mockqfilesystemwatcher.h \ + mocksearch.h \ + mocksearchhandle.h \ + mocksearchresult.h \ + mocksyntaxhighligher.h \ + processevents-utilities.h \ + sourcerangecontainer-matcher.h \ + spydummy.h \ + testenvironment.h \ !isEmpty(LIBCLANG_LIBS) { HEADERS += \ chunksreportedmonitor.h \ clangasyncjob-base.h \ + clangcompareoperators.h \ diagnosticcontainer-matcher.h \ - clangcompareoperators.h } !isEmpty(LIBTOOLING_LIBS) { HEADERS += \ + gtest-clang-printing.h \ mockrefactoringclientcallback.h \ mockrefactoringclient.h \ mockrefactoringserver.h \ - gtest-clang-printing.h \ - testclangtool.h + testclangtool.h \ } OTHER_FILES += $$files(data/*) From c3ce2dc0634dcf4fdaa4dc7cc619ea0465e40c09 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Mon, 24 Jul 2017 17:12:14 +0200 Subject: [PATCH 29/37] Clang: Sort files in *.pri/*.qbs Change-Id: I284298c926f3d445272987ee622e6fc4aba4697a Reviewed-by: Marco Bubke --- .../clangbackendipc/clangbackendipc-lib.pri | 265 +++++++++--------- src/plugins/clangcodemodel/clangcodemodel.qbs | 2 +- .../ipcsource/clangbackendclangipc-source.pri | 144 +++++----- 3 files changed, 207 insertions(+), 204 deletions(-) diff --git a/src/libs/clangbackendipc/clangbackendipc-lib.pri b/src/libs/clangbackendipc/clangbackendipc-lib.pri index e930763843a..3f3758772de 100644 --- a/src/libs/clangbackendipc/clangbackendipc-lib.pri +++ b/src/libs/clangbackendipc/clangbackendipc-lib.pri @@ -8,163 +8,164 @@ QT += network INCLUDEPATH += $$PWD -SOURCES += $$PWD/clangcodemodelserverinterface.cpp \ - $$PWD/clangcodemodelserverproxy.cpp \ - $$PWD/clangcodemodelclientinterface.cpp \ - $$PWD/cmbendmessage.cpp \ - $$PWD/cmbalivemessage.cpp \ - $$PWD/clangcodemodelclientproxy.cpp \ - $$PWD/writemessageblock.cpp \ - $$PWD/readmessageblock.cpp \ - $$PWD/ipcinterface.cpp \ - $$PWD/connectionserver.cpp \ - $$PWD/connectionclient.cpp \ - $$PWD/cmbechomessage.cpp \ - $$PWD/cmbregistertranslationunitsforeditormessage.cpp \ - $$PWD/filecontainer.cpp \ - $$PWD/cmbunregistertranslationunitsforeditormessage.cpp \ - $$PWD/cmbcompletecodemessage.cpp \ - $$PWD/cmbcodecompletedmessage.cpp \ - $$PWD/codecompletion.cpp \ - $$PWD/cmbregisterprojectsforeditormessage.cpp \ - $$PWD/cmbunregisterprojectsforeditormessage.cpp \ - $$PWD/translationunitdoesnotexistmessage.cpp \ - $$PWD/codecompletionchunk.cpp \ - $$PWD/projectpartcontainer.cpp \ - $$PWD/projectpartsdonotexistmessage.cpp \ - $$PWD/lineprefixer.cpp \ +SOURCES += \ + $$PWD/cancelmessage.cpp \ $$PWD/clangbackendipcdebugutils.cpp \ - $$PWD/diagnosticcontainer.cpp \ - $$PWD/sourcerangecontainer.cpp \ - $$PWD/sourcelocationcontainer.cpp \ - $$PWD/fixitcontainer.cpp \ - $$PWD/requestdocumentannotations.cpp \ - $$PWD/requestreferencesmessage.cpp \ - $$PWD/registerunsavedfilesforeditormessage.cpp \ - $$PWD/unregisterunsavedfilesforeditormessage.cpp \ - $$PWD/updatetranslationunitsforeditormessage.cpp \ - $$PWD/updatevisibletranslationunitsmessage.cpp \ - $$PWD/highlightingmarkcontainer.cpp \ - $$PWD/refactoringclientinterface.cpp \ - $$PWD/messageenvelop.cpp \ - $$PWD/refactoringserverinterface.cpp \ - $$PWD/refactoringserverproxy.cpp \ - $$PWD/ipcclientinterface.cpp \ - $$PWD/ipcserverinterface.cpp \ + $$PWD/clangcodemodelclientinterface.cpp \ + $$PWD/clangcodemodelclientproxy.cpp \ $$PWD/clangcodemodelconnectionclient.cpp \ + $$PWD/clangcodemodelserverinterface.cpp \ + $$PWD/clangcodemodelserverproxy.cpp \ + $$PWD/cmbalivemessage.cpp \ + $$PWD/cmbcodecompletedmessage.cpp \ + $$PWD/cmbcompletecodemessage.cpp \ + $$PWD/cmbechomessage.cpp \ + $$PWD/cmbendmessage.cpp \ + $$PWD/cmbregisterprojectsforeditormessage.cpp \ + $$PWD/cmbregistertranslationunitsforeditormessage.cpp \ + $$PWD/cmbunregisterprojectsforeditormessage.cpp \ + $$PWD/cmbunregistertranslationunitsforeditormessage.cpp \ + $$PWD/codecompletionchunk.cpp \ + $$PWD/codecompletion.cpp \ + $$PWD/connectionclient.cpp \ + $$PWD/connectionserver.cpp \ + $$PWD/diagnosticcontainer.cpp \ $$PWD/documentannotationschangedmessage.cpp \ - $$PWD/referencesmessage.cpp \ - $$PWD/refactoringclientproxy.cpp \ - $$PWD/sourcelocationscontainer.cpp \ - $$PWD/sourcelocationcontainerv2.cpp \ - $$PWD/sourcelocationsforrenamingmessage.cpp \ - $$PWD/requestsourcelocationforrenamingmessage.cpp \ - $$PWD/filepath.cpp \ - $$PWD/sourcerangescontainer.cpp \ - $$PWD/sourcefilepathcontainerbase.cpp \ - $$PWD/sourcerangecontainerv2.cpp \ $$PWD/dynamicastmatcherdiagnosticcontainer.cpp \ $$PWD/dynamicastmatcherdiagnosticcontextcontainer.cpp \ $$PWD/dynamicastmatcherdiagnosticmessagecontainer.cpp \ - $$PWD/requestsourcerangesanddiagnosticsforquerymessage.cpp \ - $$PWD/sourcerangesanddiagnosticsforquerymessage.cpp \ - $$PWD/sourcerangewithtextcontainer.cpp \ + $$PWD/filecontainer.cpp \ $$PWD/filecontainerv2.cpp \ - $$PWD/cancelmessage.cpp \ + $$PWD/filepath.cpp \ + $$PWD/fixitcontainer.cpp \ + $$PWD/highlightingmarkcontainer.cpp \ + $$PWD/ipcclientinterface.cpp \ + $$PWD/ipcinterface.cpp \ + $$PWD/ipcserverinterface.cpp \ + $$PWD/lineprefixer.cpp \ + $$PWD/messageenvelop.cpp \ $$PWD/pchmanagerclientinterface.cpp \ - $$PWD/pchmanagerserverinterface.cpp \ - $$PWD/projectpartcontainerv2.cpp \ - $$PWD/updatepchprojectpartsmessage.cpp \ - $$PWD/pchmanagerserverproxy.cpp \ $$PWD/pchmanagerclientproxy.cpp \ - $$PWD/projectpartpch.cpp \ + $$PWD/pchmanagerserverinterface.cpp \ + $$PWD/pchmanagerserverproxy.cpp \ $$PWD/precompiledheadersupdatedmessage.cpp \ + $$PWD/projectpartcontainer.cpp \ + $$PWD/projectpartcontainerv2.cpp \ + $$PWD/projectpartpch.cpp \ + $$PWD/projectpartsdonotexistmessage.cpp \ + $$PWD/readmessageblock.cpp \ + $$PWD/refactoringclientinterface.cpp \ + $$PWD/refactoringclientproxy.cpp \ + $$PWD/refactoringserverinterface.cpp \ + $$PWD/refactoringserverproxy.cpp \ + $$PWD/referencesmessage.cpp \ + $$PWD/registerunsavedfilesforeditormessage.cpp \ $$PWD/removepchprojectpartsmessage.cpp \ + $$PWD/requestdocumentannotations.cpp \ + $$PWD/requestreferencesmessage.cpp \ + $$PWD/requestsourcelocationforrenamingmessage.cpp \ + $$PWD/requestsourcerangesanddiagnosticsforquerymessage.cpp \ + $$PWD/requestsourcerangesforquerymessage.cpp \ + $$PWD/sourcefilepathcontainerbase.cpp \ + $$PWD/sourcelocationcontainer.cpp \ + $$PWD/sourcelocationcontainerv2.cpp \ + $$PWD/sourcelocationscontainer.cpp \ + $$PWD/sourcelocationsforrenamingmessage.cpp \ + $$PWD/sourcerangecontainer.cpp \ + $$PWD/sourcerangecontainerv2.cpp \ + $$PWD/sourcerangesanddiagnosticsforquerymessage.cpp \ + $$PWD/sourcerangescontainer.cpp \ $$PWD/sourcerangesforquerymessage.cpp \ - $$PWD/requestsourcerangesforquerymessage.cpp + $$PWD/sourcerangewithtextcontainer.cpp \ + $$PWD/translationunitdoesnotexistmessage.cpp \ + $$PWD/unregisterunsavedfilesforeditormessage.cpp \ + $$PWD/updatepchprojectpartsmessage.cpp \ + $$PWD/updatetranslationunitsforeditormessage.cpp \ + $$PWD/updatevisibletranslationunitsmessage.cpp \ + $$PWD/writemessageblock.cpp \ HEADERS += \ - $$PWD/clangcodemodelserverinterface.h \ - $$PWD/clangcodemodelserverproxy.h \ - $$PWD/clangcodemodelclientinterface.h \ - $$PWD/cmbendmessage.h \ - $$PWD/cmbalivemessage.h \ - $$PWD/clangcodemodelclientproxy.h \ - $$PWD/writemessageblock.h \ - $$PWD/readmessageblock.h \ - $$PWD/ipcinterface.h \ - $$PWD/connectionserver.h \ - $$PWD/connectionclient.h \ - $$PWD/cmbechomessage.h \ - $$PWD/cmbregistertranslationunitsforeditormessage.h \ - $$PWD/filecontainer.h \ - $$PWD/cmbunregistertranslationunitsforeditormessage.h \ - $$PWD/cmbcompletecodemessage.h \ - $$PWD/cmbcodecompletedmessage.h \ - $$PWD/codecompletion.h \ - $$PWD/cmbregisterprojectsforeditormessage.h \ - $$PWD/cmbunregisterprojectsforeditormessage.h \ - $$PWD/translationunitdoesnotexistmessage.h \ - $$PWD/codecompletionchunk.h \ - $$PWD/projectpartcontainer.h \ - $$PWD/projectpartsdonotexistmessage.h \ - $$PWD/clangbackendipc_global.h \ - $$PWD/lineprefixer.h \ + $$PWD/cancelmessage.h \ $$PWD/clangbackendipcdebugutils.h \ - $$PWD/diagnosticcontainer.h \ - $$PWD/sourcerangecontainer.h \ - $$PWD/sourcelocationcontainer.h \ - $$PWD/fixitcontainer.h \ - $$PWD/requestdocumentannotations.h \ - $$PWD/referencesmessage.h \ - $$PWD/requestreferencesmessage.h \ - $$PWD/registerunsavedfilesforeditormessage.h \ - $$PWD/unregisterunsavedfilesforeditormessage.h \ - $$PWD/updatetranslationunitsforeditormessage.h \ - $$PWD/updatevisibletranslationunitsmessage.h \ - $$PWD/highlightingmarkcontainer.h \ - $$PWD/messageenvelop.h \ - $$PWD/ipcclientinterface.h \ - $$PWD/ipcserverinterface.h \ + $$PWD/clangbackendipc_global.h \ + $$PWD/clangcodemodelclientinterface.h \ + $$PWD/clangcodemodelclientmessages.h \ + $$PWD/clangcodemodelclientproxy.h \ $$PWD/clangcodemodelconnectionclient.h \ + $$PWD/clangcodemodelserverinterface.h \ + $$PWD/clangcodemodelservermessages.h \ + $$PWD/clangcodemodelserverproxy.h \ + $$PWD/clangrefactoringclientmessages.h \ + $$PWD/clangrefactoringmessages.h \ + $$PWD/clangrefactoringservermessages.h \ + $$PWD/cmbalivemessage.h \ + $$PWD/cmbcodecompletedmessage.h \ + $$PWD/cmbcompletecodemessage.h \ + $$PWD/cmbechomessage.h \ + $$PWD/cmbendmessage.h \ + $$PWD/cmbregisterprojectsforeditormessage.h \ + $$PWD/cmbregistertranslationunitsforeditormessage.h \ + $$PWD/cmbunregisterprojectsforeditormessage.h \ + $$PWD/cmbunregistertranslationunitsforeditormessage.h \ + $$PWD/codecompletionchunk.h \ + $$PWD/codecompletion.h \ + $$PWD/connectionclient.h \ + $$PWD/connectionserver.h \ + $$PWD/diagnosticcontainer.h \ $$PWD/documentannotationschangedmessage.h \ - $$PWD/refactoringclientinterface.h \ - $$PWD/refactoringserverinterface.h \ - $$PWD/refactoringserverproxy.h \ - $$PWD/refactoringclientproxy.h \ - $$PWD/sourcelocationscontainer.h \ - $$PWD/sourcelocationcontainerv2.h \ - $$PWD/sourcelocationsforrenamingmessage.h \ - $$PWD/requestsourcelocationforrenamingmessage.h \ - $$PWD/filepath.h \ - $$PWD/sourcerangescontainer.h \ - $$PWD/sourcefilepathcontainerbase.h \ - $$PWD/sourcerangecontainerv2.h \ - $$PWD/dynamicmatcherdiagnostics.h \ $$PWD/dynamicastmatcherdiagnosticcontainer.h \ $$PWD/dynamicastmatcherdiagnosticcontextcontainer.h \ $$PWD/dynamicastmatcherdiagnosticmessagecontainer.h \ - $$PWD/requestsourcerangesanddiagnosticsforquerymessage.h \ - $$PWD/sourcerangesanddiagnosticsforquerymessage.h \ - $$PWD/sourcerangewithtextcontainer.h \ + $$PWD/dynamicmatcherdiagnostics.h \ + $$PWD/filecontainer.h \ $$PWD/filecontainerv2.h \ - $$PWD/cancelmessage.h \ + $$PWD/filepath.h \ + $$PWD/fixitcontainer.h \ + $$PWD/highlightingmarkcontainer.h \ + $$PWD/ipcclientinterface.h \ + $$PWD/ipcinterface.h \ + $$PWD/ipcserverinterface.h \ + $$PWD/lineprefixer.h \ + $$PWD/messageenvelop.h \ $$PWD/pchmanagerclientinterface.h \ - $$PWD/pchmanagerserverinterface.h \ - $$PWD/projectpartcontainerv2.h \ - $$PWD/updatepchprojectpartsmessage.h \ - $$PWD/pchmanagerserverproxy.h \ $$PWD/pchmanagerclientproxy.h \ - $$PWD/projectpartpch.h \ + $$PWD/pchmanagerserverinterface.h \ + $$PWD/pchmanagerserverproxy.h \ $$PWD/precompiledheadersupdatedmessage.h \ - $$PWD/stringcache.h \ + $$PWD/projectpartcontainer.h \ + $$PWD/projectpartcontainerv2.h \ + $$PWD/projectpartpch.h \ + $$PWD/projectpartsdonotexistmessage.h \ + $$PWD/readmessageblock.h \ + $$PWD/refactoringclientinterface.h \ + $$PWD/refactoringclientproxy.h \ + $$PWD/refactoringserverinterface.h \ + $$PWD/refactoringserverproxy.h \ + $$PWD/referencesmessage.h \ + $$PWD/registerunsavedfilesforeditormessage.h \ $$PWD/removepchprojectpartsmessage.h \ - $$PWD/clangcodemodelclientmessages.h \ - $$PWD/clangcodemodelservermessages.h \ + $$PWD/requestdocumentannotations.h \ + $$PWD/requestreferencesmessage.h \ + $$PWD/requestsourcelocationforrenamingmessage.h \ + $$PWD/requestsourcerangesanddiagnosticsforquerymessage.h \ + $$PWD/requestsourcerangesforquerymessage.h \ + $$PWD/sourcefilepathcontainerbase.h \ + $$PWD/sourcelocationcontainer.h \ + $$PWD/sourcelocationcontainerv2.h \ + $$PWD/sourcelocationscontainer.h \ + $$PWD/sourcelocationsforrenamingmessage.h \ + $$PWD/sourcerangecontainer.h \ + $$PWD/sourcerangecontainerv2.h \ + $$PWD/sourcerangesanddiagnosticsforquerymessage.h \ + $$PWD/sourcerangescontainer.h \ $$PWD/sourcerangesforquerymessage.h \ - $$PWD/clangrefactoringmessages.h \ - $$PWD/clangrefactoringclientmessages.h \ - $$PWD/clangrefactoringservermessages.h \ - $$PWD/requestsourcerangesforquerymessage.h + $$PWD/sourcerangewithtextcontainer.h \ + $$PWD/stringcache.h \ + $$PWD/translationunitdoesnotexistmessage.h \ + $$PWD/unregisterunsavedfilesforeditormessage.h \ + $$PWD/updatepchprojectpartsmessage.h \ + $$PWD/updatetranslationunitsforeditormessage.h \ + $$PWD/updatevisibletranslationunitsmessage.h \ + $$PWD/writemessageblock.h \ contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols diff --git a/src/plugins/clangcodemodel/clangcodemodel.qbs b/src/plugins/clangcodemodel/clangcodemodel.qbs index e6a2f1cde28..eb46d8f2bd0 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.qbs +++ b/src/plugins/clangcodemodel/clangcodemodel.qbs @@ -43,9 +43,9 @@ QtcPlugin { "clangassistproposalmodel.h", "clangbackendipcintegration.cpp", "clangbackendipcintegration.h", - "clangcodemodel.qrc", "clangcodemodelplugin.cpp", "clangcodemodelplugin.h", + "clangcodemodel.qrc", "clangcompletionassistinterface.cpp", "clangcompletionassistinterface.h", "clangcompletionassistprocessor.cpp", diff --git a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri index c598eece8b5..06be9be18de 100644 --- a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri +++ b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri @@ -1,101 +1,103 @@ INCLUDEPATH += $$PWD -HEADERS += $$PWD/clangcodemodelserver.h \ - $$PWD/codecompleter.h \ - $$PWD/clangstring.h \ - $$PWD/clangcodecompleteresults.h \ - $$PWD/codecompletionsextractor.h \ - $$PWD/unsavedfile.h \ - $$PWD/unsavedfiles.h \ - $$PWD/projects.h \ - $$PWD/clangdocuments.h \ - $$PWD/projectpart.h \ - $$PWD/codecompletionchunkconverter.h \ - $$PWD/diagnosticset.h \ - $$PWD/diagnostic.h \ - $$PWD/sourcelocation.h \ - $$PWD/sourcerange.h \ - $$PWD/fixit.h \ - $$PWD/diagnosticsetiterator.h \ - $$PWD/clangfilesystemwatcher.h \ - $$PWD/commandlinearguments.h \ - $$PWD/cursor.h \ - $$PWD/skippedsourceranges.h \ - $$PWD/clangdocument.h \ - $$PWD/clangtranslationunitupdater.h \ - $$PWD/clangtype.h \ - $$PWD/highlightingmark.h \ - $$PWD/highlightingmarks.h \ - $$PWD/highlightingmarksiterator.h \ - $$PWD/utf8positionfromlinecolumn.h \ +HEADERS += \ $$PWD/clangasyncjob.h \ $$PWD/clangbackend_global.h \ + $$PWD/clangclock.h \ + $$PWD/clangcodecompleteresults.h \ + $$PWD/clangcodemodelserver.h \ $$PWD/clangcompletecodejob.h \ $$PWD/clangcreateinitialdocumentpreamblejob.h \ + $$PWD/clangdocument.h \ + $$PWD/clangdocumentprocessor.h \ + $$PWD/clangdocumentprocessors.h \ + $$PWD/clangdocuments.h \ + $$PWD/clangexceptions.h \ $$PWD/clangfilepath.h \ + $$PWD/clangfilesystemwatcher.h \ $$PWD/clangiasyncjob.h \ $$PWD/clangjobcontext.h \ $$PWD/clangjobqueue.h \ $$PWD/clangjobrequest.h \ $$PWD/clangjobs.h \ + $$PWD/clangparsesupportivetranslationunitjob.h \ + $$PWD/clangreferencescollector.h \ + $$PWD/clangreparsesupportivetranslationunitjob.h \ $$PWD/clangrequestdocumentannotationsjob.h \ + $$PWD/clangrequestreferencesjob.h \ + $$PWD/clangstring.h \ + $$PWD/clangsupportivetranslationunitinitializer.h \ $$PWD/clangtranslationunit.h \ + $$PWD/clangtranslationunits.h \ + $$PWD/clangtranslationunitupdater.h \ + $$PWD/clangtype.h \ $$PWD/clangunsavedfilesshallowarguments.h \ $$PWD/clangupdatedocumentannotationsjob.h \ - $$PWD/clangexceptions.h \ - $$PWD/clangdocumentprocessor.h \ - $$PWD/clangdocumentprocessors.h \ - $$PWD/clangtranslationunits.h \ - $$PWD/clangclock.h \ - $$PWD/clangsupportivetranslationunitinitializer.h \ - $$PWD/clangparsesupportivetranslationunitjob.h \ - $$PWD/clangreparsesupportivetranslationunitjob.h \ - $$PWD/clangrequestreferencesjob.h \ - $$PWD/clangreferencescollector.h + $$PWD/codecompleter.h \ + $$PWD/codecompletionchunkconverter.h \ + $$PWD/codecompletionsextractor.h \ + $$PWD/commandlinearguments.h \ + $$PWD/cursor.h \ + $$PWD/diagnostic.h \ + $$PWD/diagnosticset.h \ + $$PWD/diagnosticsetiterator.h \ + $$PWD/fixit.h \ + $$PWD/highlightingmark.h \ + $$PWD/highlightingmarks.h \ + $$PWD/highlightingmarksiterator.h \ + $$PWD/projectpart.h \ + $$PWD/projects.h \ + $$PWD/skippedsourceranges.h \ + $$PWD/sourcelocation.h \ + $$PWD/sourcerange.h \ + $$PWD/unsavedfile.h \ + $$PWD/unsavedfiles.h \ + $$PWD/utf8positionfromlinecolumn.h \ -SOURCES += $$PWD/clangcodemodelserver.cpp \ - $$PWD/codecompleter.cpp \ +SOURCES += \ $$PWD/clangcodecompleteresults.cpp \ - $$PWD/codecompletionsextractor.cpp \ - $$PWD/unsavedfile.cpp \ - $$PWD/unsavedfiles.cpp \ - $$PWD/projects.cpp \ - $$PWD/clangdocuments.cpp \ - $$PWD/projectpart.cpp \ - $$PWD/codecompletionchunkconverter.cpp \ - $$PWD/diagnosticset.cpp \ - $$PWD/diagnostic.cpp \ - $$PWD/sourcelocation.cpp \ - $$PWD/sourcerange.cpp \ - $$PWD/fixit.cpp \ - $$PWD/clangfilesystemwatcher.cpp \ - $$PWD/commandlinearguments.cpp \ - $$PWD/cursor.cpp \ - $$PWD/skippedsourceranges.cpp \ - $$PWD/clangdocument.cpp \ - $$PWD/clangtranslationunitupdater.cpp \ - $$PWD/clangtype.cpp \ - $$PWD/highlightingmark.cpp \ - $$PWD/highlightingmarks.cpp \ - $$PWD/utf8positionfromlinecolumn.cpp \ + $$PWD/clangcodemodelserver.cpp \ $$PWD/clangcompletecodejob.cpp \ $$PWD/clangcreateinitialdocumentpreamblejob.cpp \ + $$PWD/clangdocument.cpp \ + $$PWD/clangdocumentprocessor.cpp \ + $$PWD/clangdocumentprocessors.cpp \ + $$PWD/clangdocuments.cpp \ + $$PWD/clangexceptions.cpp \ $$PWD/clangfilepath.cpp \ + $$PWD/clangfilesystemwatcher.cpp \ $$PWD/clangiasyncjob.cpp \ $$PWD/clangjobcontext.cpp \ $$PWD/clangjobqueue.cpp \ $$PWD/clangjobrequest.cpp \ $$PWD/clangjobs.cpp \ + $$PWD/clangparsesupportivetranslationunitjob.cpp \ + $$PWD/clangreferencescollector.cpp \ + $$PWD/clangreparsesupportivetranslationunitjob.cpp \ $$PWD/clangrequestdocumentannotationsjob.cpp \ + $$PWD/clangrequestreferencesjob.cpp \ + $$PWD/clangsupportivetranslationunitinitializer.cpp \ $$PWD/clangtranslationunit.cpp \ + $$PWD/clangtranslationunits.cpp \ + $$PWD/clangtranslationunitupdater.cpp \ + $$PWD/clangtype.cpp \ $$PWD/clangunsavedfilesshallowarguments.cpp \ $$PWD/clangupdatedocumentannotationsjob.cpp \ - $$PWD/clangexceptions.cpp \ - $$PWD/clangdocumentprocessor.cpp \ - $$PWD/clangdocumentprocessors.cpp \ - $$PWD/clangtranslationunits.cpp \ - $$PWD/clangsupportivetranslationunitinitializer.cpp \ - $$PWD/clangparsesupportivetranslationunitjob.cpp \ - $$PWD/clangreparsesupportivetranslationunitjob.cpp \ - $$PWD/clangrequestreferencesjob.cpp \ - $$PWD/clangreferencescollector.cpp + $$PWD/codecompleter.cpp \ + $$PWD/codecompletionchunkconverter.cpp \ + $$PWD/codecompletionsextractor.cpp \ + $$PWD/commandlinearguments.cpp \ + $$PWD/cursor.cpp \ + $$PWD/diagnostic.cpp \ + $$PWD/diagnosticset.cpp \ + $$PWD/fixit.cpp \ + $$PWD/highlightingmark.cpp \ + $$PWD/highlightingmarks.cpp \ + $$PWD/projectpart.cpp \ + $$PWD/projects.cpp \ + $$PWD/skippedsourceranges.cpp \ + $$PWD/sourcelocation.cpp \ + $$PWD/sourcerange.cpp \ + $$PWD/unsavedfile.cpp \ + $$PWD/unsavedfiles.cpp \ + $$PWD/utf8positionfromlinecolumn.cpp \ From 8997386675b17394bb78e0c3fb813d538d205aa8 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 24 Jul 2017 13:28:57 +0200 Subject: [PATCH 30/37] QmlDesigner: Polish the formeditor split toolbuttons a bit This gives them a similar look of other toolbuttons in Qt Creator. Change-Id: Ib3163ff6c1eab2bd26e46d1136de5fa474dea66d Reviewed-by: Tim Jenssen --- src/plugins/qmldesigner/switchsplittabwidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/switchsplittabwidget.cpp b/src/plugins/qmldesigner/switchsplittabwidget.cpp index c9e5ec4993e..8b36f0e7e37 100644 --- a/src/plugins/qmldesigner/switchsplittabwidget.cpp +++ b/src/plugins/qmldesigner/switchsplittabwidget.cpp @@ -81,7 +81,7 @@ SwitchSplitTabWidget::SwitchSplitTabWidget(QWidget *parent) QToolButton *horizontalButton = new QToolButton; horizontalButton->setObjectName("centralTabBar"); horizontalButton->setIcon(Utils::Icon({{QLatin1String(":/qmldesigner/images/spliteditorvertically.png"), - Utils::Theme::TextColorNormal}}, Utils::Icon::Tint).icon()); + Utils::Theme::IconsBaseColor}}).icon()); horizontalButton->setIconSize(QSize(8, 16)); connect(horizontalButton, &QToolButton::clicked, [this] () { m_splitter->setOrientation(Qt::Vertical); @@ -91,7 +91,7 @@ SwitchSplitTabWidget::SwitchSplitTabWidget(QWidget *parent) QToolButton *verticalButton = new QToolButton; verticalButton->setObjectName("centralTabBar"); verticalButton->setIcon(Utils::Icon({{QLatin1String(":/qmldesigner/images/spliteditorhorizontally.png"), - Utils::Theme::TextColorNormal}}, Utils::Icon::Tint).icon()); + Utils::Theme::IconsBaseColor}}).icon()); verticalButton->setIconSize(QSize(8, 16)); connect(verticalButton, &QToolButton::clicked, [this] () { m_splitter->setOrientation(Qt::Horizontal); From 5df0f97d2f4f90decbc2fb263704755857416846 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 24 Jul 2017 19:29:51 +0200 Subject: [PATCH 31/37] Core: Tweak the wizard icon text overlay Increasing the text size a bit, making the text darker and making the margin proportional to the image size (resolution independent). Change-Id: I029b57e2bf1c355f35161e5f8810dddea4114047 Reviewed-by: Tim Jenssen --- src/plugins/coreplugin/dialogs/newdialog.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/plugins/coreplugin/dialogs/newdialog.cpp b/src/plugins/coreplugin/dialogs/newdialog.cpp index 6ffb1e89b7d..2254f6c5b62 100644 --- a/src/plugins/coreplugin/dialogs/newdialog.cpp +++ b/src/plugins/coreplugin/dialogs/newdialog.cpp @@ -376,14 +376,16 @@ static QIcon iconWithText(const QIcon &icon, const QString &text) QIcon iconWithText; for (const QSize &pixmapSize : icon.availableSizes()) { QPixmap pixmap = icon.pixmap(pixmapSize); + const int fontSize = pixmap.height() / 4; + const int margin = pixmap.height() / 8; QFont font; - font.setPixelSize(qMin(pixmap.height(), pixmap.width()) / 5); + font.setPixelSize(fontSize); + font.setStretch(85); QPainter p(&pixmap); - p.setPen(qRgb(0x6b, 0x70, 0x80)); p.setFont(font); QTextOption textOption(Qt::AlignHCenter | Qt::AlignBottom); textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); - p.drawText(pixmap.rect().adjusted(9, 10, -9, -10), text, textOption); + p.drawText(pixmap.rect().adjusted(margin, margin, -margin, -margin), text, textOption); iconWithText.addPixmap(pixmap); } return iconWithText; From e8e46ab553bce9aac9adcaf2ac4ee1207b69ac93 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 21 Jul 2017 14:50:23 +0200 Subject: [PATCH 32/37] Plugins: Fix that mimetype definition was not valid JSON JSON officially does not support multiline strings, so we should use the same mechanism that we already use for the plugin description (i.e. additionally support arrays of strings which are interpreted as lines). This just happens to work because Qt's JSON parser eats it without choking. Change-Id: I25ef04600b209775c5a7af916c687fda4a8b1a4d Reviewed-by: Oswald Buddenhagen Reviewed-by: Christian Stenger --- src/libs/extensionsystem/pluginspec.cpp | 12 +- src/libs/extensionsystem/pluginspec.h | 2 + src/plugins/android/Android.json.in | 20 +- src/plugins/clearcase/ClearCase.json.in | 18 +- .../CMakeProjectManager.json.in | 30 +-- src/plugins/coreplugin/coreplugin.cpp | 5 +- src/plugins/cpptools/CppTools.json.in | 176 +++++++++--------- src/plugins/cvs/CVS.json.in | 18 +- src/plugins/debugger/Debugger.json.in | 32 ++-- .../GenericProjectManager.json.in | 50 ++--- src/plugins/git/Git.json.in | 32 ++-- src/plugins/glsleditor/GLSLEditor.json.in | 74 ++++---- src/plugins/imageviewer/ImageViewer.json.in | 18 +- src/plugins/modeleditor/ModelEditor.json.in | 20 +- src/plugins/nim/Nim.json.in | 40 ++-- src/plugins/perforce/Perforce.json.in | 24 +-- src/plugins/pythoneditor/PythonEditor.json.in | 30 +-- .../QmakeProjectManager.json.in | 70 +++---- src/plugins/qmljstools/QmlJSTools.json.in | 82 ++++---- .../QmlProjectManager.json.in | 20 +- src/plugins/qtsupport/QtSupport.json.in | 42 ++--- .../resourceeditor/ResourceEditor.json.in | 20 +- src/plugins/scxmleditor/ScxmlEditor.json.in | 20 +- src/plugins/subversion/Subversion.json.in | 18 +- src/plugins/tasklist/TaskList.json.in | 22 +-- 25 files changed, 448 insertions(+), 447 deletions(-) diff --git a/src/libs/extensionsystem/pluginspec.cpp b/src/libs/extensionsystem/pluginspec.cpp index 19be010c4de..cde1903099f 100644 --- a/src/libs/extensionsystem/pluginspec.cpp +++ b/src/libs/extensionsystem/pluginspec.cpp @@ -31,6 +31,7 @@ #include "pluginmanager.h" #include +#include #include #include @@ -630,12 +631,9 @@ static inline QString msgInvalidFormat(const char *key, const QString &content) .arg(QLatin1String(key), content); } -static inline bool readMultiLineString(const QJsonValue &value, QString *out) +bool PluginSpec::readMultiLineString(const QJsonValue &value, QString *out) { - if (!out) { - qCWarning(pluginLog) << Q_FUNC_INFO << "missing output parameter"; - return false; - } + QTC_ASSERT(out, return false); if (value.isString()) { *out = value.toString(); } else if (value.isArray()) { @@ -737,7 +735,7 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData) copyright = value.toString(); value = metaData.value(QLatin1String(DESCRIPTION)); - if (!value.isUndefined() && !readMultiLineString(value, &description)) + if (!value.isUndefined() && !PluginSpec::readMultiLineString(value, &description)) return reportError(msgValueIsNotAString(DESCRIPTION)); value = metaData.value(QLatin1String(URL)); @@ -751,7 +749,7 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData) category = value.toString(); value = metaData.value(QLatin1String(LICENSE)); - if (!value.isUndefined() && !readMultiLineString(value, &license)) + if (!value.isUndefined() && !PluginSpec::readMultiLineString(value, &license)) return reportError(msgValueIsNotAMultilineString(LICENSE)); value = metaData.value(QLatin1String(PLATFORM)); diff --git a/src/libs/extensionsystem/pluginspec.h b/src/libs/extensionsystem/pluginspec.h index 0462acddefe..da89ff6029f 100644 --- a/src/libs/extensionsystem/pluginspec.h +++ b/src/libs/extensionsystem/pluginspec.h @@ -131,6 +131,8 @@ public: bool hasError() const; QString errorString() const; + static bool readMultiLineString(const QJsonValue &value, QString *out); + private: PluginSpec(); diff --git a/src/plugins/android/Android.json.in b/src/plugins/android/Android.json.in index 43268da1c2b..eda39dd3a24 100644 --- a/src/plugins/android/Android.json.in +++ b/src/plugins/android/Android.json.in @@ -17,14 +17,14 @@ \"Url\" : \"http://necessitas.kde.org\", $$dependencyList, - \"Mimetypes\" : \" - - - - Android manifest file - - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" Android manifest file\", + \" \", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/clearcase/ClearCase.json.in b/src/plugins/clearcase/ClearCase.json.in index b9153225d75..24384b8ab66 100644 --- a/src/plugins/clearcase/ClearCase.json.in +++ b/src/plugins/clearcase/ClearCase.json.in @@ -19,13 +19,13 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - - - - ClearCase submit template - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" ClearCase submit template\", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/cmakeprojectmanager/CMakeProjectManager.json.in b/src/plugins/cmakeprojectmanager/CMakeProjectManager.json.in index 5d75c622a8d..5bf0dc4ad5c 100644 --- a/src/plugins/cmakeprojectmanager/CMakeProjectManager.json.in +++ b/src/plugins/cmakeprojectmanager/CMakeProjectManager.json.in @@ -17,19 +17,19 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - - - - - CMake Project file - - - - - CMake Project file - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" \", + \" CMake Project file\", + \" \", + \" \", + \" \", + \" \", + \" CMake Project file\", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index fed19490ca6..a51d418a6c7 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -131,8 +131,9 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) continue; const QJsonObject metaData = plugin->metaData(); const QJsonValue mimetypes = metaData.value("Mimetypes"); - if (mimetypes.isString()) - Utils::addMimeTypes(plugin->name() + ".mimetypes", mimetypes.toString().trimmed().toUtf8()); + QString mimetypeString; + if (ExtensionSystem::PluginSpec::readMultiLineString(mimetypes, &mimetypeString)) + Utils::addMimeTypes(plugin->name() + ".mimetypes", mimetypeString.trimmed().toUtf8()); } if (ThemeEntry::availableThemes().isEmpty()) { diff --git a/src/plugins/cpptools/CppTools.json.in b/src/plugins/cpptools/CppTools.json.in index a9af2e54d6d..c95a262683f 100644 --- a/src/plugins/cpptools/CppTools.json.in +++ b/src/plugins/cpptools/CppTools.json.in @@ -18,101 +18,101 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - - - - C source code - - - - + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" C source code\", + \" \", + \" \", + \" \", + \" \", - - - NVIDIA CUDA C source code - - + \" \", + \" \", + \" NVIDIA CUDA C source code\", + \" \", + \" \", - - C header - - - - + \" \", + \" C header\", + \" \", + \" \", + \" \", + \" \", - - - - C++ header - - - - - - - - - - - - - - - + \" \", + \" \", + \" \", + \" C++ header\", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", - - C++ source code - - - - - - - - - - - - - - - - - + \" \", + \" C++ source code\", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", - - Qt documentation file - - - + \" \", + \" Qt documentation file\", + \" \", + \" \", + \" \", - - Qt MOC file - - - - + \" \", + \" Qt MOC file\", + \" \", + \" \", + \" \", + \" \", - - Objective-C++ source code - - - - + \" \", + \" Objective-C++ source code\", + \" \", + \" \", + \" \", + \" \", - - Objective-C source code - - - - - - + \" \", + \" Objective-C source code\", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", - - \" + \"\" + ] } diff --git a/src/plugins/cvs/CVS.json.in b/src/plugins/cvs/CVS.json.in index d18e228f1de..1efdd73d48d 100644 --- a/src/plugins/cvs/CVS.json.in +++ b/src/plugins/cvs/CVS.json.in @@ -17,13 +17,13 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - - - - CVS submit template - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" CVS submit template\", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/debugger/Debugger.json.in b/src/plugins/debugger/Debugger.json.in index 458d1a84564..c4ed7f18e3f 100644 --- a/src/plugins/debugger/Debugger.json.in +++ b/src/plugins/debugger/Debugger.json.in @@ -41,20 +41,20 @@ ], $$dependencyList, - \"Mimetypes\" : \" - - - - - Assembler - - - - - - Qt Creator Generic Assembler - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" \", + \" Assembler\", + \" \", + \" \", + \" \", + \" \", + \" \", + \" Qt Creator Generic Assembler\", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/genericprojectmanager/GenericProjectManager.json.in b/src/plugins/genericprojectmanager/GenericProjectManager.json.in index cc9ce119d4b..306d2fcaa48 100644 --- a/src/plugins/genericprojectmanager/GenericProjectManager.json.in +++ b/src/plugins/genericprojectmanager/GenericProjectManager.json.in @@ -17,34 +17,34 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - + \"Mimetypes\" : [ + \"\", - - - - Generic Qt Creator Project file - - + \"\", + \" \", + \" \", + \" Generic Qt Creator Project file\", + \" \", + \" \", - - - Generic Project Files - - + \" \", + \" \", + \" Generic Project Files\", + \" \", + \" \", - - - Generic Project Include Paths - - + \" \", + \" \", + \" Generic Project Include Paths\", + \" \", + \" \", - - - Generic Project Configuration File - - + \" \", + \" \", + \" Generic Project Configuration File\", + \" \", + \" \", - - \" + \"\" + ] } diff --git a/src/plugins/git/Git.json.in b/src/plugins/git/Git.json.in index c2680577baf..ebbee5d4096 100644 --- a/src/plugins/git/Git.json.in +++ b/src/plugins/git/Git.json.in @@ -17,20 +17,20 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - - - - - Git Commit File - - - - - - Git Commit File - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" \", + \" Git Commit File\", + \" \", + \" \", + \" \", + \" \", + \" \", + \" Git Commit File\", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/glsleditor/GLSLEditor.json.in b/src/plugins/glsleditor/GLSLEditor.json.in index 915ae7ae029..09814901a26 100644 --- a/src/plugins/glsleditor/GLSLEditor.json.in +++ b/src/plugins/glsleditor/GLSLEditor.json.in @@ -17,48 +17,48 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - - + \"Mimetypes\" : [ + \"\", + \"\", - - - - GLSL Shader file - - - + \" \", + \" \", + \" \", + \" GLSL Shader file\", + \" \", + \" \", + \" \", - - - GLSL Fragment Shader file - - + \" \", + \" \", + \" GLSL Fragment Shader file\", + \" \", + \" \", - - - GLSL/ES Fragment Shader file - - + \" \", + \" \", + \" GLSL/ES Fragment Shader file\", + \" \", + \" \", - - - GLSL Vertex Shader file - - + \" \", + \" \", + \" GLSL Vertex Shader file\", + \" \", + \" \", - - - GLSL/ES Vertex Shader file - - + \" \", + \" \", + \" GLSL/ES Vertex Shader file\", + \" \", + \" \", - - - GLSL/ES Geometry Shader file - - + \" \", + \" \", + \" GLSL/ES Geometry Shader file\", + \" \", + \" \", - - \" + \"\" + ] } diff --git a/src/plugins/imageviewer/ImageViewer.json.in b/src/plugins/imageviewer/ImageViewer.json.in index 685dff9a9f1..59fa5f72826 100644 --- a/src/plugins/imageviewer/ImageViewer.json.in +++ b/src/plugins/imageviewer/ImageViewer.json.in @@ -17,15 +17,15 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - - + \"Mimetypes\" : [ + \"\", + \"\", - - WebP Image file - - + \" \", + \" WebP Image file\", + \" \", + \" \", - - \" + \"\" + ] } diff --git a/src/plugins/modeleditor/ModelEditor.json.in b/src/plugins/modeleditor/ModelEditor.json.in index 44558589be4..8fc6c019cb0 100644 --- a/src/plugins/modeleditor/ModelEditor.json.in +++ b/src/plugins/modeleditor/ModelEditor.json.in @@ -18,14 +18,14 @@ \"Experimental\" : true, $$dependencyList, - \"Mimetypes\" : \" - - - - - Qt Creator Model File - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" \", + \" Qt Creator Model File\", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/nim/Nim.json.in b/src/plugins/nim/Nim.json.in index 3fc6a651350..9f44b2ce45c 100644 --- a/src/plugins/nim/Nim.json.in +++ b/src/plugins/nim/Nim.json.in @@ -18,27 +18,27 @@ \"Experimental\" : true, $$dependencyList, - \"Mimetypes\" : \" - - + \"Mimetypes\" : [ + \"\", + \"\", - - - Nim project file - - + \" \", + \" \", + \" Nim project file\", + \" \", + \" \", - - - Nim source file - - + \" \", + \" \", + \" Nim source file \", + \" \", + \" \", - - - Nim script file - - - - \" + \" \", + \" \", + \" Nim script file \", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/perforce/Perforce.json.in b/src/plugins/perforce/Perforce.json.in index 7d408c00e4d..cb92d2542d0 100644 --- a/src/plugins/perforce/Perforce.json.in +++ b/src/plugins/perforce/Perforce.json.in @@ -17,16 +17,16 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - - - - Perforce submit template - - - - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" Perforce submit template\", + \" \", + \" \", + \" \", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/pythoneditor/PythonEditor.json.in b/src/plugins/pythoneditor/PythonEditor.json.in index 5f3709887d9..5416dbfa63c 100644 --- a/src/plugins/pythoneditor/PythonEditor.json.in +++ b/src/plugins/pythoneditor/PythonEditor.json.in @@ -17,19 +17,19 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - - - - - Python source file without console - - - - - Qt Creator Python project file - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" \", + \" Python source file without console\", + \" \", + \" \", + \" \", + \" \", + \" Qt Creator Python project file\", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/qmakeprojectmanager/QmakeProjectManager.json.in b/src/plugins/qmakeprojectmanager/QmakeProjectManager.json.in index ae3d11d8c0e..6f4826ed55d 100644 --- a/src/plugins/qmakeprojectmanager/QmakeProjectManager.json.in +++ b/src/plugins/qmakeprojectmanager/QmakeProjectManager.json.in @@ -17,39 +17,39 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - - - - - Qt Project file - - - - - Qt Project include file - - - - - Qt Project feature file - - - - - Qt Project configuration file - - - - - Qt Project cache file - - - - - Qt Project stash file - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" \", + \" Qt Project file\", + \" \", + \" \", + \" \", + \" \", + \" Qt Project include file\", + \" \", + \" \", + \" \", + \" \", + \" Qt Project feature file\", + \" \", + \" \", + \" \", + \" \", + \" Qt Project configuration file\", + \" \", + \" \", + \" \", + \" \", + \" Qt Project cache file\", + \" \", + \" \", + \" \", + \" \", + \" Qt Project stash file\", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/qmljstools/QmlJSTools.json.in b/src/plugins/qmljstools/QmlJSTools.json.in index 1d50eae3c48..1861e87513e 100644 --- a/src/plugins/qmljstools/QmlJSTools.json.in +++ b/src/plugins/qmljstools/QmlJSTools.json.in @@ -18,45 +18,45 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - - - - - - - QML file - - - - - - Qt Build Suite file - - - - - - QtQuick Designer ui file - - - - - - Qt Creator Qt UI project file - - - - - - QML file - - - - - JSON file - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" \", + \" \", + \" \", + \" QML file\", + \" \", + \" \", + \" \", + \" \", + \" \", + \" Qt Build Suite file\", + \" \", + \" \", + \" \", + \" \", + \" \", + \" QtQuick Designer ui file\", + \" \", + \" \", + \" \", + \" \", + \" \", + \" Qt Creator Qt UI project file\", + \" \", + \" \", + \" \", + \" \", + \" \", + \" QML file\", + \" \", + \" \", + \" \", + \" \", + \" JSON file\", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/qmlprojectmanager/QmlProjectManager.json.in b/src/plugins/qmlprojectmanager/QmlProjectManager.json.in index fcd607a2287..329e4b603db 100644 --- a/src/plugins/qmlprojectmanager/QmlProjectManager.json.in +++ b/src/plugins/qmlprojectmanager/QmlProjectManager.json.in @@ -17,15 +17,15 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - + \"Mimetypes\" : [ + \"\", - - - - QML Project file - - - - \" + \"\", + \" \", + \" \", + \" QML Project file\", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/qtsupport/QtSupport.json.in b/src/plugins/qtsupport/QtSupport.json.in index b62bb1b29d5..1447c9c14b2 100644 --- a/src/plugins/qtsupport/QtSupport.json.in +++ b/src/plugins/qtsupport/QtSupport.json.in @@ -18,25 +18,25 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - - - - Linguist compiled translations - - - - Linguist source translations - - - - - - - SCXML State Chart - - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" Linguist compiled translations\", + \" \", + \" \", + \" \", + \" Linguist source translations\", + \" \", + \" \", + \" \", + \" \", + \" \", + \" \", + \" SCXML State Chart\", + \" \", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/resourceeditor/ResourceEditor.json.in b/src/plugins/resourceeditor/ResourceEditor.json.in index 6bf2776a0c1..dc0a5c8822a 100644 --- a/src/plugins/resourceeditor/ResourceEditor.json.in +++ b/src/plugins/resourceeditor/ResourceEditor.json.in @@ -17,14 +17,14 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - - - - - Qt Resource file - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" \", + \" Qt Resource file\", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/scxmleditor/ScxmlEditor.json.in b/src/plugins/scxmleditor/ScxmlEditor.json.in index 1e48677f5fb..1218f4129b4 100644 --- a/src/plugins/scxmleditor/ScxmlEditor.json.in +++ b/src/plugins/scxmleditor/ScxmlEditor.json.in @@ -18,14 +18,14 @@ \"Experimental\" : true, $$dependencyList, - \"Mimetypes\" : \" - - - - - SCXML file - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" \", + \" SCXML file\", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/subversion/Subversion.json.in b/src/plugins/subversion/Subversion.json.in index a31c9dd38b8..8196061d642 100644 --- a/src/plugins/subversion/Subversion.json.in +++ b/src/plugins/subversion/Subversion.json.in @@ -17,13 +17,13 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - - - - Subversion submit template - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" Subversion submit template\", + \" \", + \" \", + \"\" + ] } diff --git a/src/plugins/tasklist/TaskList.json.in b/src/plugins/tasklist/TaskList.json.in index 202bf41b2a7..7c1f6f4ee2e 100644 --- a/src/plugins/tasklist/TaskList.json.in +++ b/src/plugins/tasklist/TaskList.json.in @@ -16,15 +16,15 @@ \"Url\" : \"http://www.qt.io\", $$dependencyList, - \"Mimetypes\" : \" - - - - - Qt Creator task list file - - - - - \" + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" \", + \" Qt Creator task list file\", + \" \", + \" \", + \" \", + \"\" + ] } From 3ed88cda2f44ce97569f59c4d83dc930016af92b Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 25 Jul 2017 07:52:08 +0200 Subject: [PATCH 33/37] GenericHighlighter: Update supported kate styles Change-Id: I016b25c56b31c615e208e86e690fc7408c9e5384 Reviewed-by: Orgad Shaneh --- .../texteditor/generichighlighter/highlighter.cpp | 10 ++++++++++ .../texteditor/generichighlighter/highlighter.h | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/src/plugins/texteditor/generichighlighter/highlighter.cpp b/src/plugins/texteditor/generichighlighter/highlighter.cpp index 418d58de891..b2a12fb02fd 100644 --- a/src/plugins/texteditor/generichighlighter/highlighter.cpp +++ b/src/plugins/texteditor/generichighlighter/highlighter.cpp @@ -109,6 +109,11 @@ static TextStyle styleForFormat(int format) case Highlighter::Others: return C_TEXT; case Highlighter::Identifier: return C_LOCAL; case Highlighter::Documentation: return C_DOXYGEN_COMMENT; + case Highlighter::ControlFlow: return C_KEYWORD; + case Highlighter::Preprocessor: return C_PREPROCESSOR; + case Highlighter::VerbatimString: return C_STRING; + case Highlighter::SpecialString: return C_STRING; + case Highlighter::Constant: return C_KEYWORD; case Highlighter::TextFormatIdCount: QTC_CHECK(false); // should never get here return C_TEXT; @@ -168,6 +173,11 @@ KateFormatMap::KateFormatMap() m_ids.insert(QLatin1String("dsOthers"), Highlighter::Others); m_ids.insert(QLatin1String("dsIdentifier"), Highlighter::Identifier); m_ids.insert(QLatin1String("dsDocumentation"), Highlighter::Documentation); + m_ids.insert(QLatin1String("dsControlFlow"), Highlighter::ControlFlow); + m_ids.insert(QLatin1String("dsPreprocessor"), Highlighter::Preprocessor); + m_ids.insert(QLatin1String("dsVerbatimString"), Highlighter::VerbatimString); + m_ids.insert(QLatin1String("dsSpecialString"), Highlighter::SpecialString); + m_ids.insert(QLatin1String("dsConstant"), Highlighter::Constant); } Q_GLOBAL_STATIC(KateFormatMap, kateFormatMap) diff --git a/src/plugins/texteditor/generichighlighter/highlighter.h b/src/plugins/texteditor/generichighlighter/highlighter.h index 0baa0c03ad8..4c69d9977b6 100644 --- a/src/plugins/texteditor/generichighlighter/highlighter.h +++ b/src/plugins/texteditor/generichighlighter/highlighter.h @@ -91,6 +91,11 @@ public: Others, Identifier, Documentation, + ControlFlow, + Preprocessor, + VerbatimString, + SpecialString, + Constant, TextFormatIdCount }; From 68fe72e99abebd4602103b523b6c46eabaf3c667 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Tue, 25 Jul 2017 09:03:08 +0200 Subject: [PATCH 34/37] Define COPYRIGHT_YEAR in build files This allows us to use the copyright year also in the following patch that adds it as metadata to the windows executable. Ideally we'd unify IDE_YEAR and IDE_AUTHOR (because they're only used together anyway) but that would break translations. Change-Id: If0f84eaeb22e9ba71b2b29798324b76a91eda78f Reviewed-by: Orgad Shaneh Reviewed-by: Eike Ziller --- qbs/modules/qtc/qtc.qbs | 2 ++ qtcreator.pri | 1 + src/app/app_version.h.in | 2 +- src/app/app_version_header.qbs | 2 ++ 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs index 1d9e0deac24..ab1c2aee8ae 100644 --- a/qbs/modules/qtc/qtc.qbs +++ b/qbs/modules/qtc/qtc.qbs @@ -17,6 +17,8 @@ Module { property string qtcreator_compat_version: ide_compat_version_major + '.' + ide_compat_version_minor + '.' + ide_compat_version_release + property string qtcreator_copyright_year: '2017' + property string libDirName: "lib" property string ide_app_path: qbs.targetOS.contains("macos") ? "" : "bin" property string ide_app_target: qbs.targetOS.contains("macos") ? "Qt Creator" : "qtcreator" diff --git a/qtcreator.pri b/qtcreator.pri index 24853d5ba27..7a94a1595dd 100644 --- a/qtcreator.pri +++ b/qtcreator.pri @@ -5,6 +5,7 @@ QTCREATOR_VERSION = 4.3.82 QTCREATOR_COMPAT_VERSION = 4.3.82 VERSION = $$QTCREATOR_VERSION QTCREATOR_DISPLAY_VERSION = 4.4.0-beta1 +QTCREATOR_COPYRIGHT_YEAR = 2017 BINARY_ARTIFACTS_BRANCH = 4.4 CONFIG += c++14 diff --git a/src/app/app_version.h.in b/src/app/app_version.h.in index 19bff44d49a..97fd0735a4c 100644 --- a/src/app/app_version.h.in +++ b/src/app/app_version.h.in @@ -42,7 +42,7 @@ namespace Constants { const char * const IDE_VERSION_LONG = IDE_VERSION_STR; const char * const IDE_VERSION_DISPLAY = STRINGIFY(IDE_VERSION_DISPLAY_DEF); const char * const IDE_AUTHOR = \"The Qt Company Ltd\"; -const char * const IDE_YEAR = \"2017\"; +const char * const IDE_YEAR = \"$${QTCREATOR_COPYRIGHT_YEAR}\"; #ifdef IDE_REVISION const char * const IDE_REVISION_STR = STRINGIFY(IDE_REVISION); diff --git a/src/app/app_version_header.qbs b/src/app/app_version_header.qbs index 5730be75429..e6903d6cc52 100644 --- a/src/app/app_version_header.qbs +++ b/src/app/app_version_header.qbs @@ -42,6 +42,8 @@ Product { + product.moduleProperty("qtc", "ide_version_minor") + "\n"); content = content.replace(/(\n#define IDE_VERSION_RELEASE) .+\n/, "$1 " + product.moduleProperty("qtc", "ide_version_release") + "\n"); + content = content.replace(/(\n#define IDE_COPYRIGHT_YEAR) .+\n/, "$1 " + + product.moduleProperty("qtc", "qtcreator_copyright_year") + "\n"); file = new TextFile(output.filePath, TextFile.WriteOnly); file.truncate(); file.write(content); From 7d8847101d4b91c11dc89826b0058257bd1fc95d Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 21 Jul 2017 15:41:33 +0200 Subject: [PATCH 35/37] Add name, version as metadata to Windows executable The description and version is seen e.g. in the file dialogs, but also in the task manager and crash dialogs. Change-Id: I65f7076a55ecbdcaa6b7c9ab57fecaab59bcaa08 Reviewed-by: Orgad Shaneh Reviewed-by: Christian Kandeler Reviewed-by: Joerg Bornemann --- src/app/app.pro | 6 ++++++ src/app/app.qbs | 11 ++++++++++- src/app/qtcreator.rc | 24 ++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/app/app.pro b/src/app/app.pro index 58dca7ba050..1414e7d7fca 100644 --- a/src/app/app.pro +++ b/src/app/app.pro @@ -20,6 +20,12 @@ QT_BREAKPAD_ROOT_PATH = $$(QT_BREAKPAD_ROOT_PATH) include($$QT_BREAKPAD_ROOT_PATH/qtbreakpad.pri) } win32 { + # We need the version in two separate formats for the .rc file + # RC_VERSION=4,3,82,0 (quadruple) + # RC_VERSION_STRING="4.4.0-beta1" (free text) + DEFINES += RC_VERSION=$$replace(QTCREATOR_VERSION, "\\.", ","),0 \ + RC_VERSION_STRING=\\\"$${QTCREATOR_DISPLAY_VERSION}\\\" \ + RC_COPYRIGHT='"\\\"2008-$${QTCREATOR_COPYRIGHT_YEAR} The Qt Company Ltd\\\""' RC_FILE = qtcreator.rc } else:macx { LIBS += -framework CoreFoundation diff --git a/src/app/app.qbs b/src/app/app.qbs index 0af41ca20d9..b3023fcbe74 100644 --- a/src/app/app.qbs +++ b/src/app/app.qbs @@ -41,7 +41,6 @@ QtcProduct { "Info.plist", "main.cpp", "qtcreator.xcassets", - "qtcreator.rc", "../shared/qtsingleapplication/qtsingleapplication.h", "../shared/qtsingleapplication/qtsingleapplication.cpp", "../shared/qtsingleapplication/qtlocalpeer.h", @@ -51,6 +50,16 @@ QtcProduct { "../tools/qtcreatorcrashhandler/crashhandlersetup.h" ] + Group { + // We need the version in two separate formats for the .rc file + // RC_VERSION=4,3,82,0 (quadruple) + // RC_VERSION_STRING="4.4.0-beta1" (free text) + cpp.defines: outer.concat(["RC_VERSION=" + qtc.qtcreator_version.replace(/\./g, ",") + ",0", + "RC_VERSION_STRING=\"" + qtc.qtcreator_display_version + "\"", + "RC_COPYRIGHT=\"2008-" + qtc.qtcreator_copyright_year + " The Qt Company Ltd\""]) + files: "qtcreator.rc" + } + Group { name: "qtcreator.sh" condition: qbs.targetOS.contains("unix") && !qbs.targetOS.contains("macos") diff --git a/src/app/qtcreator.rc b/src/app/qtcreator.rc index b23a85f3222..89f03c4708c 100644 --- a/src/app/qtcreator.rc +++ b/src/app/qtcreator.rc @@ -1,3 +1,5 @@ +#include + IDI_ICON1 ICON DISCARDABLE "qtcreator.ico" IDI_ICON2 ICON DISCARDABLE "winicons/c.ico" IDI_ICON3 ICON DISCARDABLE "winicons/cpp.ico" @@ -6,3 +8,25 @@ IDI_ICON5 ICON DISCARDABLE "winicons/ui.ico" IDI_ICON6 ICON DISCARDABLE "winicons/pro.ico" IDI_ICON7 ICON DISCARDABLE "winicons/pri.ico" IDI_ICON8 ICON DISCARDABLE "winicons/qml.ico" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION RC_VERSION + PRODUCTVERSION RC_VERSION +{ + BLOCK "StringFileInfo" + { + // U.S. English - Windows, Multilingual + BLOCK "040904E4" + { + VALUE "FileDescription", "Qt Creator" + VALUE "FileVersion", RC_VERSION_STRING + VALUE "ProductName", "Qt Creator" + VALUE "ProductVersion", RC_VERSION_STRING + VALUE "LegalCopyright", RC_COPYRIGHT + } + } + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x409, 1252 // 1252 = 0x04E4 + } +} From 336f54def454e83ac34a946dcda448615a6453d8 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Mon, 24 Jul 2017 12:53:12 +0200 Subject: [PATCH 36/37] CMake: Fix progress calculation in server-mode Add unit test to make sure this stays fixed. Task-number: QTCREATORBUG-18624 Change-Id: Ieeb41982418481223d9ebf8f5c6ec4b3b78bfe00 Reviewed-by: Tim Jenssen Reviewed-by: Eike Ziller --- .../cmakeprojectmanager/cmakeprojectplugin.h | 3 + .../cmakeprojectmanager/servermodereader.cpp | 67 ++++++++++++++++++- .../cmakeprojectmanager/servermodereader.h | 8 +++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.h b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.h index 99c63d10e11..de3112184a0 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.h @@ -61,6 +61,9 @@ private slots: void testCMakeProjectImporterToolChain_data(); void testCMakeProjectImporterToolChain(); + + void testServerModeReaderProgress_data(); + void testServerModeReaderProgress(); #endif private: diff --git a/src/plugins/cmakeprojectmanager/servermodereader.cpp b/src/plugins/cmakeprojectmanager/servermodereader.cpp index e366d4f6ecc..8ce3efe9c34 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.cpp +++ b/src/plugins/cmakeprojectmanager/servermodereader.cpp @@ -406,8 +406,7 @@ void ServerModeReader::handleProgress(int min, int cur, int max, const QString & if (!m_future) return; - int progress = m_progressStepMinimum - + (((max - min) / (cur - min)) * (m_progressStepMaximum - m_progressStepMinimum)); + const int progress = calculateProgress(m_progressStepMinimum, min, cur, max, m_progressStepMaximum); m_future->setProgressValue(progress); } @@ -419,6 +418,14 @@ void ServerModeReader::handleSignal(const QString &signal, const QVariantMap &da emit dirty(); } +int ServerModeReader::calculateProgress(const int minRange, const int min, const int cur, const int max, const int maxRange) +{ + if (minRange == maxRange || min == max) + return minRange; + const int clampedCur = std::min(std::max(cur, min), max); + return minRange + ((clampedCur - min) / (max - min)) * (maxRange - minRange); +} + void ServerModeReader::extractCodeModelData(const QVariantMap &data) { const QVariantList configs = data.value("configurations").toList(); @@ -771,3 +778,59 @@ void ServerModeReader::addHeaderNodes(ProjectNode *root, const QList } // namespace Internal } // namespace CMakeProjectManager + +#if defined(WITH_TESTS) + +#include "cmakeprojectplugin.h" +#include + +namespace CMakeProjectManager { +namespace Internal { + +void CMakeProjectPlugin::testServerModeReaderProgress_data() +{ + QTest::addColumn("minRange"); + QTest::addColumn("min"); + QTest::addColumn("cur"); + QTest::addColumn("max"); + QTest::addColumn("maxRange"); + QTest::addColumn("expected"); + + QTest::newRow("empty range") << 100 << 10 << 11 << 20 << 100 << 100; + QTest::newRow("one range (low)") << 0 << 10 << 11 << 20 << 1 << 0; + QTest::newRow("one range (high)") << 20 << 10 << 19 << 20 << 20 << 20; + QTest::newRow("large range") << 30 << 10 << 11 << 20 << 100000 << 30; + + QTest::newRow("empty progress") << -5 << 10 << 10 << 10 << 99995 << -5; + QTest::newRow("one progress (low)") << 42 << 10 << 10 << 11 << 100042 << 42; + QTest::newRow("one progress (high)") << 0 << 10 << 11 << 11 << 100000 << 100000; + QTest::newRow("large progress") << 0 << 10 << 10 << 11 << 100000 << 0; + + QTest::newRow("cur too low") << 0 << 10 << 9 << 100 << 100000 << 0; + QTest::newRow("cur too high") << 0 << 10 << 101 << 100 << 100000 << 100000; + QTest::newRow("cur much too low") << 0 << 10 << -1000 << 100 << 100000 << 0; + QTest::newRow("cur much too high") << 0 << 10 << 1110000 << 100 << 100000 << 100000; +} + +void CMakeProjectPlugin::testServerModeReaderProgress() +{ + QFETCH(int, minRange); + QFETCH(int, min); + QFETCH(int, cur); + QFETCH(int, max); + QFETCH(int, maxRange); + QFETCH(int, expected); + + ServerModeReader reader; + const int r = reader.calculateProgress(minRange, min, cur, max, maxRange); + + QCOMPARE(r, expected); + + QVERIFY(r <= maxRange); + QVERIFY(r >= minRange); +} + +} // namespace Internal +} // namespace CMakeProjectManager + +#endif diff --git a/src/plugins/cmakeprojectmanager/servermodereader.h b/src/plugins/cmakeprojectmanager/servermodereader.h index 4265d9627c3..461bc00e05e 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.h +++ b/src/plugins/cmakeprojectmanager/servermodereader.h @@ -67,6 +67,10 @@ private: void handleProgress(int min, int cur, int max, const QString &inReplyTo); void handleSignal(const QString &signal, const QVariantMap &data); + int calculateProgress(const int minRange, const int min, + const int cur, + const int max, const int maxRange); + struct Target; struct Project; @@ -151,6 +155,10 @@ private: QList m_fileGroups; CMakeParser m_parser; + +#if defined(WITH_TESTS) + friend class CMakeProjectPlugin; +#endif }; } // namespace Internal From 3881ff94f7c6386fe43c8e8cc2e47e317a382641 Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Mon, 24 Jul 2017 15:27:19 +0200 Subject: [PATCH 37/37] Android: Fix sdkmanager timing out on slower machines sdkmanager times out on slower machines or with slower network connection. Increase the timeout and show timeout message box Task-number: QTCREATORBUG-18458 Change-Id: I9118024ec1438ef9c18842df2f7431e696c73f92 Reviewed-by: Leena Miettinen Reviewed-by: Tobias Hunger --- src/plugins/android/androidconfigurations.cpp | 8 ++++--- src/plugins/android/androidsdkmanager.cpp | 24 ++++++++++++------- src/plugins/android/androidsdkmanager.h | 2 +- src/plugins/android/androidtoolmanager.cpp | 8 ++++++- src/plugins/android/androidtoolmanager.h | 2 +- .../qmakeandroidbuildapkstep.cpp | 7 ++++++ 6 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index be5f6df9619..ccefeef4e24 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -347,8 +347,10 @@ void AndroidConfig::updateAvailableSdkPlatforms() const m_availableSdkPlatforms.clear(); AndroidSdkManager sdkManager(*this); - m_availableSdkPlatforms = sdkManager.availableSdkPlatforms(); - m_availableSdkPlatformsUpToDate = true; + bool success = false; + m_availableSdkPlatforms = sdkManager.availableSdkPlatforms(&success); + if (success) + m_availableSdkPlatformsUpToDate = true; } QStringList AndroidConfig::apiLevelNamesFor(const QList &platforms) @@ -358,7 +360,7 @@ QStringList AndroidConfig::apiLevelNamesFor(const QList &platforms) QString AndroidConfig::apiLevelNameFor(const SdkPlatform &platform) { - return QLatin1String("android-") + QString::number(platform.apiLevel); + return platform.apiLevel > 0 ? QString("android-%1").arg(platform.apiLevel) : ""; } QList AndroidConfig::sdkTargets(int minApiLevel) const diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index 0ed23660a61..c28fef27a18 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -50,6 +50,8 @@ const char installLocationKey[] = "Installed Location:"; const char apiLevelPropertyKey[] = "AndroidVersion.ApiLevel"; const char abiPropertyKey[] = "SystemImage.Abi"; +const int sdkManagerCmdTimeoutS = 60; + using namespace Utils; /*! @@ -72,11 +74,14 @@ static bool valueForKey(QString key, const QString &line, QString *value = nullp \c true if the command is successfully executed. Output is copied into \a output. The function blocks the calling thread. */ -static bool sdkManagerCommand(const AndroidConfig config, const QStringList &args, QString *output) +static bool sdkManagerCommand(const AndroidConfig config, const QStringList &args, QString *output, + int timeout = sdkManagerCmdTimeoutS) { QString sdkManagerToolPath = config.sdkManagerToolPath().toString(); SynchronousProcess proc; - SynchronousProcessResponse response = proc.runBlocking(sdkManagerToolPath, args); + proc.setTimeoutS(timeout); + proc.setTimeOutMessageBoxEnabled(true); + SynchronousProcessResponse response = proc.run(sdkManagerToolPath, args); if (response.result == SynchronousProcessResponse::Finished) { if (output) *output = response.allOutput(); @@ -132,10 +137,6 @@ AndroidSdkManager::AndroidSdkManager(const AndroidConfig &config): m_config(config), m_parser(new SdkManagerOutputParser) { - QString packageListing; - if (sdkManagerCommand(config, QStringList({"--list", "--verbose"}), &packageListing)) { - m_parser->parsePackageListing(packageListing); - } } AndroidSdkManager::~AndroidSdkManager() @@ -143,13 +144,20 @@ AndroidSdkManager::~AndroidSdkManager() } -SdkPlatformList AndroidSdkManager::availableSdkPlatforms() +SdkPlatformList AndroidSdkManager::availableSdkPlatforms(bool *ok) { + bool success = false; if (m_config.sdkToolsVersion() < sdkManagerIntroVersion) { AndroidToolManager toolManager(m_config); - return toolManager.availableSdkPlatforms(); + return toolManager.availableSdkPlatforms(ok); } + QString packageListing; + if (sdkManagerCommand(m_config, QStringList({"--list", "--verbose"}), &packageListing)) + m_parser->parsePackageListing(packageListing); + + if (ok) + *ok = success; return m_parser->m_installedPlatforms; } diff --git a/src/plugins/android/androidsdkmanager.h b/src/plugins/android/androidsdkmanager.h index 2c111480723..b1da078b6ef 100644 --- a/src/plugins/android/androidsdkmanager.h +++ b/src/plugins/android/androidsdkmanager.h @@ -40,7 +40,7 @@ public: AndroidSdkManager(const AndroidConfig &config); ~AndroidSdkManager(); - SdkPlatformList availableSdkPlatforms(); + SdkPlatformList availableSdkPlatforms(bool *ok = nullptr); private: const AndroidConfig &m_config; diff --git a/src/plugins/android/androidtoolmanager.cpp b/src/plugins/android/androidtoolmanager.cpp index 19f7cbc97b9..39fa2a2c426 100644 --- a/src/plugins/android/androidtoolmanager.cpp +++ b/src/plugins/android/androidtoolmanager.cpp @@ -97,16 +97,22 @@ AndroidToolManager::~AndroidToolManager() } -SdkPlatformList AndroidToolManager::availableSdkPlatforms() const +SdkPlatformList AndroidToolManager::availableSdkPlatforms(bool *ok) const { + bool success = false; SdkPlatformList list; QString targetListing; if (androidToolCommand(m_config.androidToolPath(), QStringList({"list", "target"}), androidToolEnvironment(), &targetListing)) { m_parser->parseTargetListing(targetListing, m_config.sdkLocation(), &list); + success = true; } else { qCDebug(androidToolLog) << "Android tool target listing failed"; } + + if (ok) + *ok = success; + return list; } diff --git a/src/plugins/android/androidtoolmanager.h b/src/plugins/android/androidtoolmanager.h index befb095b92a..faaa9428ab6 100644 --- a/src/plugins/android/androidtoolmanager.h +++ b/src/plugins/android/androidtoolmanager.h @@ -48,7 +48,7 @@ public: AndroidToolManager(const AndroidConfig &config); ~AndroidToolManager(); - SdkPlatformList availableSdkPlatforms() const; + SdkPlatformList availableSdkPlatforms(bool *ok = nullptr) const; void launchAvdManager() const; QFuture createAvd(AndroidConfig::CreateAvdInfo info) const; diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp b/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp index ce087ff9df2..4ca9ef9653a 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp +++ b/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp @@ -158,6 +158,13 @@ bool QmakeAndroidBuildApkStep::init(QList &earlierSteps) return true; } + QString buildTargetSdk = AndroidManager::buildTargetSDK(target()); + if (buildTargetSdk.isEmpty()) { + emit addOutput(tr("Android build SDK not defined. Check Android settings."), + OutputFormat::Stderr); + return false; + } + QStringList arguments; arguments << QLatin1String("--input") << inputFile