diff --git a/src/plugins/clangformat/CMakeLists.txt b/src/plugins/clangformat/CMakeLists.txt index 5db5f8111a7..49eeb53e342 100644 --- a/src/plugins/clangformat/CMakeLists.txt +++ b/src/plugins/clangformat/CMakeLists.txt @@ -19,3 +19,12 @@ extend_qtc_plugin(ClangFormat CONDITION UNIX AND NOT APPLE PROPERTIES LINK_FLAGS "-Wl,--exclude-libs,ALL" ) + +extend_qtc_plugin(ClangFormat + CONDITION WITH_TESTS + SOURCES + tests/clangformat-test.cpp + tests/clangformat-test.h + DEFINES + TESTDATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/tests/data" +) diff --git a/src/plugins/clangformat/clangformat.pro b/src/plugins/clangformat/clangformat.pro index da7645613cf..6ff219e6b1b 100644 --- a/src/plugins/clangformat/clangformat.pro +++ b/src/plugins/clangformat/clangformat.pro @@ -32,3 +32,9 @@ HEADERS += \ FORMS += \ clangformatchecks.ui \ clangformatconfigwidget.ui + +equals(TEST, 1) { + DEFINES += TESTDATA_DIR=\"R\\\"xxx($$PWD/tests/data)xxx\\\"\" + HEADERS += tests/clangformat-test.h + SOURCES += tests/clangformat-test.cpp +} diff --git a/src/plugins/clangformat/clangformat.qbs b/src/plugins/clangformat/clangformat.qbs index fcd77b7c1b4..cbb93d7c77d 100644 --- a/src/plugins/clangformat/clangformat.qbs +++ b/src/plugins/clangformat/clangformat.qbs @@ -44,4 +44,16 @@ QtcPlugin { "clangformatutils.h", "clangformatutils.cpp", ] + + Group { + name: "Tests" + prefix: "tests/" + condition: qtc.testsEnabled + cpp.defines: outer.concat('TESTDATA_DIR="' + sourceDirectory + "/tests/data" + '"') + files: [ + "clangformat-test.cpp", + "clangformat-test.h", + "data/.clang-format", + ] + } } diff --git a/src/plugins/clangformat/clangformatplugin.cpp b/src/plugins/clangformat/clangformatplugin.cpp index 87322175726..0fbc44eefe9 100644 --- a/src/plugins/clangformat/clangformatplugin.cpp +++ b/src/plugins/clangformat/clangformatplugin.cpp @@ -29,6 +29,7 @@ #include "clangformatconstants.h" #include "clangformatindenter.h" #include "clangformatutils.h" +#include "tests/clangformat-test.h" #include @@ -160,4 +161,13 @@ bool ClangFormatPlugin::initialize(const QStringList &arguments, QString *errorS return true; } +QVector ClangFormatPlugin::createTestObjects() const +{ + return { +#ifdef WITH_TESTS + new Internal::ClangFormatTest, +#endif + }; +} + } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatplugin.h b/src/plugins/clangformat/clangformatplugin.h index 716417d4425..0a7b774ce4f 100644 --- a/src/plugins/clangformat/clangformatplugin.h +++ b/src/plugins/clangformat/clangformatplugin.h @@ -35,6 +35,7 @@ class ClangFormatPlugin : public ExtensionSystem::IPlugin Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "ClangFormat.json") bool initialize(const QStringList &arguments, QString *errorString) final; + QVector createTestObjects() const override; }; } // namespace ClangTools diff --git a/src/plugins/clangformat/tests/clangformat-test.cpp b/src/plugins/clangformat/tests/clangformat-test.cpp new file mode 100644 index 00000000000..3bef6506795 --- /dev/null +++ b/src/plugins/clangformat/tests/clangformat-test.cpp @@ -0,0 +1,649 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "clangformat-test.h" + +#include "../clangformatbaseindenter.h" + +#include +#include +#include + +#include +#include +#include + +namespace ClangFormat::Internal { + +class ClangFormatTestIndenter : public ClangFormatBaseIndenter +{ +public: + ClangFormatTestIndenter(QTextDocument *doc) : ClangFormatBaseIndenter(doc) {} + +private: + Utils::optional tabSettings() const override { return {}; } +}; + +class ClangFormatExtendedTestIndenter : public ClangFormatTestIndenter +{ +public: + ClangFormatExtendedTestIndenter(QTextDocument *doc) : ClangFormatTestIndenter(doc) {} + +private: + bool formatWhileTyping() const override { return true; } +}; + +ClangFormatTest::ClangFormatTest() + : m_doc(new QTextDocument(this)), + m_cursor(new QTextCursor(m_doc)), + m_indenter(new ClangFormatTestIndenter(m_doc)), + m_extendedIndenter(new ClangFormatExtendedTestIndenter(m_doc)) +{ + m_indenter->setFileName(Utils::FilePath::fromString(TESTDATA_DIR "/test.cpp")); + m_extendedIndenter->setFileName(Utils::FilePath::fromString(TESTDATA_DIR "/test.cpp")); +} + +ClangFormatTest::~ClangFormatTest() +{ + delete m_extendedIndenter; + delete m_indenter; + delete m_cursor; +} + +void ClangFormatTest::insertLines(const std::vector &lines) +{ + m_doc->clear(); + m_cursor->setPosition(0); + for (std::size_t lineNumber = 1; lineNumber <= lines.size(); ++lineNumber) { + if (lineNumber > 1) + m_cursor->insertBlock(); + m_cursor->insertText(lines[lineNumber - 1]); + } + m_cursor->setPosition(0); + m_cursor->movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + +} + +std::vector ClangFormatTest::documentLines() const +{ + std::vector result; + const int lines = m_doc->blockCount(); + result.reserve(static_cast(lines)); + for (int line = 0; line < lines; ++line) + result.push_back(m_doc->findBlockByNumber(line).text()); + return result; +} + +void ClangFormatTest::testIndentBasicFile() +{ + insertLines({"int main()", "{", "int a;", "}"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"int main()", "{", " int a;", "}"})); +} + +void ClangFormatTest::testIndentEmptyLine() +{ + insertLines({"int main()", "{", "", "}"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"int main()", "{", " ", "}"})); +} + +void ClangFormatTest::testIndentLambda() +{ + insertLines({"int b = foo([](){", "", "});"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"int b = foo([](){", " ", "});"})); +} + +void ClangFormatTest::testIndentNestedIfElse() +{ + insertLines({"if (a)", + "if (b)", + "foo();", + "else", + "bar();", + "else", + "baz();"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{ + "if (a)", + " if (b)", + " foo();", + " else", + " bar();", + "else", + " baz();"})); +} + +void ClangFormatTest::testIndentInitializerListInArguments() +{ + insertLines({"foo(arg1,", "args,", "{1, 2});"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"foo(arg1,", " args,", " {1, 2});"})); +} + +void ClangFormatTest::testIndentLambdaWithReturnType() +{ + insertLines({"{", "auto lambda = []() -> bool {", "", "};", "}"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"{", " auto lambda = []() -> bool {", " ", " };", "}"})); +} + +void ClangFormatTest::testIndentFunctionArgumentLambdaWithNextLineScope() +{ + insertLines({"foo([]()", "{", "", "});"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"foo([]()", " {", " ", " });"})); +} + +void ClangFormatTest::testIndentScopeAsFunctionArgument() +{ + insertLines({"foo(", "{", "", "});"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"foo(", " {", " ", " });"})); +} + +void ClangFormatTest::testIndentInsideStructuredBinding() +{ + insertLines({"auto [a,", "b] = c;"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"auto [a,", " b] = c;"})); +} + +void ClangFormatTest::testIndentMacrosWithoutSemicolon() +{ + insertLines({"void test()", + "{", + "ASSERT(1);", + "ASSERT(2)", + "ASSERT(3)", + "ASSERT(4);", + "ASSERT(5)", + "}"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{ + "void test()", + "{", + " ASSERT(1);", + " ASSERT(2)", + " ASSERT(3)", + " ASSERT(4);", + " ASSERT(5)", + "}"})); +} + +void ClangFormatTest::testIndentAfterSquareBracesInsideBraceInitialization() +{ + insertLines({"int foo() {", "char a = char{b[0]};", "int c;", "}"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"int foo() {", " char a = char{b[0]};", " int c;", "}"})); +} + +void ClangFormatTest::testIndentStringLiteralContinuation() +{ + insertLines({"foo(bar, \"foo\"", "\"bar\");"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"foo(bar, \"foo\"", " \"bar\");"})); +} + +void ClangFormatTest::testIndentTemplateparameters() +{ + insertLines({"using Alias = Template"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{ + "using Alias = Template"})); +} + +void ClangFormatTest::testNoExtraIndentAfterStatementInsideSquareBraces() +{ + insertLines({"{", " x[y=z];", " int a;", "}"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"{", " x[y=z];", " int a;", "}"})); +} + +void ClangFormatTest::testNoExtraIndentAfterBraceInitialization() +{ + insertLines({"int j{i?5:10};", "return 0;"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"int j{i?5:10};", "return 0;"})); +} + +void ClangFormatTest::testIndentMultipleEmptyLines() +{ + insertLines({"{", "", "", "", "}"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"{", " ", " ", " ", "}"})); +} + +void ClangFormatTest::testIndentEmptyLineAndKeepPreviousEmptyLines() +{ + insertLines({"{", " ", " ", "", "}"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(3), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"{", " ", " ", " ", "}"})); +} + +void ClangFormatTest::testIndentOnElectricCharacterButNotRemoveEmptyLinesBefore() +{ + insertLines({"{", " ", " ", "if ()", "}"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(3), '(', TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"{", " ", " ", " if ()", "}"})); +} + +void ClangFormatTest::testIndentAfterExtraSpaceInpreviousLine() +{ + insertLines({"if (a ", "&& b)"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"if (a", " && b)"})); +} + +void ClangFormatTest::testIndentEmptyLineInsideParentheses() +{ + insertLines({"if (a ", "", " && b)"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"if (a", " ", " && b)"})); +} + +void ClangFormatTest::testIndentInsideIf() +{ + insertLines({"if (a && b", ")"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"if (a && b", " )"})); +} + +void ClangFormatTest::testIndentInsideIf2() +{ + insertLines({"if (a && b &&", ")"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"if (a && b &&", " )"})); +} + +void ClangFormatTest::testIndentInsideIf3() +{ + insertLines({"if (a || b", ")"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"if (a || b", " )"})); +} + +void ClangFormatTest::testEmptyLineInInitializerList() +{ + insertLines({"Bar foo{a,", "", "};"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"Bar foo{a,", " ", "};"})); +} + +void ClangFormatTest::testIndentClosingBraceAfterComma() +{ + insertLines({"Bar foo{a,", "}"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"Bar foo{a,", " }"})); +} + +void ClangFormatTest::testDoNotIndentClosingBraceAfterSemicolon() +{ + insertLines({"{", " a;" "}"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"{", " a;" "}"})); +} + +void ClangFormatTest::testIndentAfterIf() +{ + insertLines({"if (a)", ""}); + m_indenter->indentBlock(m_doc->findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"if (a)", " "})); +} + +void ClangFormatTest::testIndentAfterElse() +{ + insertLines({"if (a)", " foo();", "else", ""}); + m_indenter->indentBlock(m_doc->findBlockByNumber(3), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"if (a)", " foo();", "else", " "})); +} + +void ClangFormatTest::testSameIndentAfterSecondNewLineAfterIf() +{ + insertLines({"if (a)", " ", ""}); + m_indenter->indentBlock(m_doc->findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"if (a)", " ", " "})); +} + +void ClangFormatTest::testIndentAfterNewLineInsideIfWithFunctionCall() +{ + insertLines({"if (foo()", ")"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"if (foo()", " )"})); +} + +void ClangFormatTest::testSameIndentAfterSecondNewLineInsideIfWithFunctionCall() +{ + insertLines({"if (foo()", " ", ")"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"if (foo()", " ", " )"})); +} + +void ClangFormatTest::testSameIndentAfterSecondNonEmptyNewLineInsideIfWithFunctionCall() +{ + insertLines({"if (foo()", " ", "bar)"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"if (foo()", " ", " bar)"})); +} + +void ClangFormatTest::testSameIndentsOnNewLinesAfterComments() +{ + insertLines({"namespace {} //comment", "", ""}); + m_indenter->indentBlock(m_doc->findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"namespace {} //comment", "", ""})); +} + +void ClangFormatTest::testIndentAfterEmptyLineAfterAngledIncludeDirective() +{ + insertLines({"#include ", "", "using namespace std;"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"#include ", "", "using namespace std;"})); +} + +void ClangFormatTest::testIndentAfterEmptyLineAfterQuotedIncludeDirective() +{ + insertLines({"#include \"foo.h\"", "", "using namespace std;"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"#include \"foo.h\"", "", "using namespace std;"})); +} + +void ClangFormatTest::testIndentAfterLineComment() +{ + insertLines({"int foo()", + "{", + " // Comment", + " ", + " if (", + "}"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(4), '(', TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{ + "int foo()", + "{", + " // Comment", + " ", + " if (", + "}"})); +} + +void ClangFormatTest::testIndentAfterBlockComment() +{ + insertLines({"int foo()", + "{", + " bar(); /* Comment */", + " ", + " if (", + "}"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(4), '(', TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{ + "int foo()", + "{", + " bar(); /* Comment */", + " ", + " if (", + "}"})); +} + +void ClangFormatTest::testIndentAfterIfdef() +{ + insertLines({"int foo()", + "{", + "#ifdef FOO", + "#endif", + " ", + " if (", + "}"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(5), '(', TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{ + "int foo()", + "{", + "#ifdef FOO", + "#endif", + " ", + " if (", + "}"})); +} + +void ClangFormatTest::testIndentAfterEmptyLineInTheFileBeginning() +{ + insertLines({"", "void foo()"}); + m_indenter->indentBlock(m_doc->findBlockByNumber(1), ')', TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"", "void foo()"})); +} + +void ClangFormatTest::testIndentFunctionBodyButNotFormatBeforeIt() +{ + insertLines({"int foo(int a, int b,", + " int c, int d", + " ) {", + "", + "}"}); + m_extendedIndenter->indentBlock(m_doc->findBlockByNumber(3), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{ + "int foo(int a, int b,", + " int c, int d", + " ) {", + " ", + "}"})); +} + +void ClangFormatTest::testIndentAfterFunctionBodyAndNotFormatBefore() +{ + insertLines({"int foo(int a, int b, int c, int d)", + "{", + " ", + "}"}); + m_extendedIndenter->indentBlock(m_doc->findBlockByNumber(3), + QChar::Null, + TextEditor::TabSettings(), + m_doc->characterCount() - 3); + QCOMPARE(documentLines(), (std::vector{ + "int foo(int a, int b, int c, int d)", + "{", + " ", + "}"})); +} + +void ClangFormatTest::testReformatToEmptyFunction() +{ + insertLines({"int foo(int a, int b, int c, int d)", "{", " ", "}"}); + m_extendedIndenter->indentBlock(m_doc->findBlockByNumber(3), '}', TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"int foo(int a, int b, int c, int d) {}"})); +} + +void ClangFormatTest::testReformatToNonEmptyFunction() +{ + insertLines({"int foo(int a, int b) {", "", "}"}); + m_extendedIndenter->indentBlock(m_doc->findBlockByNumber(1), QChar::Null, + TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"int foo(int a, int b) {", " ", "}"})); +} + +void ClangFormatTest::testIndentClosingScopeAndFormatBeforeIt() +{ + insertLines({"if(a && b", " &&c && d", " ) {", "", "}"}); + m_extendedIndenter->indentBlock(m_doc->findBlockByNumber(4), '}', TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"if (a && b && c && d) {", "}"})); +} + +void ClangFormatTest::testDoNotFormatAfterTheFirstColon() +{ + insertLines({"{", " Qt:", "}"}); + m_extendedIndenter->indentBlock(m_doc->findBlockByNumber(1), ':', TextEditor::TabSettings(), 9); + QCOMPARE(documentLines(), (std::vector{"{", " Qt:", "}"})); +} + +void ClangFormatTest::testOnlyIndentIncompleteStatementOnElectricalCharacter() +{ + insertLines({"{bar();", "foo()", "}"}); + m_extendedIndenter->indentBlock(m_doc->findBlockByNumber(1), '(', TextEditor::TabSettings(), 12); + QCOMPARE(documentLines(), (std::vector{"{bar();", " foo()", "}"})); +} + +void ClangFormatTest::testIndentAndFormatCompleteStatementOnSemicolon() +{ + insertLines({"{bar();", "foo();", "}"}); + m_extendedIndenter->indentBlock(m_doc->findBlockByNumber(1), ';', TextEditor::TabSettings(), 14); + QCOMPARE(documentLines(), (std::vector{"{", " bar();", " foo();", "}"})); +} + +void ClangFormatTest::testIndentAndFormatCompleteStatementOnClosingScope() +{ + insertLines({"{bar();", "foo();", "}"}); + m_extendedIndenter->indentBlock(m_doc->findBlockByNumber(1), '}', TextEditor::TabSettings(), 16); + QCOMPARE(documentLines(), (std::vector{"{", " bar();", " foo();", "}"})); +} + +void ClangFormatTest::testOnlyIndentClosingParenthesis() +{ + insertLines({"foo(a,", " ", ")"}); + m_extendedIndenter->indentBlock(m_doc->findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"foo(a,", " ", " )"})); +} + +void ClangFormatTest::testEquallyIndentInsideParenthesis() +{ + insertLines({"if (a", ")"}); + m_extendedIndenter->indentBlock(m_doc->findBlockByNumber(1), QChar::Null, + TextEditor::TabSettings()); + auto linesAfterFirstLineBreak = documentLines(); + insertLines({"if (a", " ", ")"}); + m_extendedIndenter->indentBlock(m_doc->findBlockByNumber(2), + QChar::Null, TextEditor::TabSettings()); + QCOMPARE(linesAfterFirstLineBreak, (std::vector{"if (a", " )"})); + QCOMPARE(documentLines(), (std::vector{"if (a", " ", " )"})); +} + +void ClangFormatTest::testFormatBasicFile() +{ + insertLines({"int main()", "{", "int a;", "}"}); + m_indenter->format({{1, 4}}); + QCOMPARE(documentLines(), (std::vector{"int main()", "{", " int a;", "}"})); +} + +void ClangFormatTest::testFormatEmptyLine() +{ + insertLines({"int main()", "{", "", "}"}); + m_indenter->format({{1, 4}}); + QCOMPARE(documentLines(), (std::vector{"int main() {}"})); +} + +void ClangFormatTest::testFormatLambda() +{ + insertLines({"int b = foo([](){", "", "});"}); + m_indenter->format({{1, 3}}); + QCOMPARE(documentLines(), (std::vector{"int b = foo([]() {", "", "});"})); +} + +void ClangFormatTest::testFormatInitializerListInArguments() +{ + insertLines({"foo(arg1,", "args,", "{1, 2});"}); + m_indenter->format({{1, 3}}); + QCOMPARE(documentLines(), (std::vector{"foo(arg1, args, {1, 2});"})); +} + +void ClangFormatTest::testFormatFunctionArgumentLambdaWithScope() +{ + insertLines({"foo([]()", "{", "", "});"}); + m_indenter->format({{1, 4}}); + QCOMPARE(documentLines(), (std::vector{"foo([]() {", "", "});"})); +} + +void ClangFormatTest::testFormatScopeAsFunctionArgument() +{ + insertLines({"foo(", "{", "", "});"}); + m_indenter->format({{1, 4}}); + QCOMPARE(documentLines(), (std::vector{"foo({", "", "});"})); +} + +void ClangFormatTest::testFormatStructuredBinding() +{ + insertLines({"auto [a,", "b] = c;"}); + m_indenter->format({{1, 2}}); + QCOMPARE(documentLines(), (std::vector{"auto [a, b] = c;"})); +} + +void ClangFormatTest::testFormatStringLiteralContinuation() +{ + insertLines({"foo(bar, \"foo\"", "\"bar\");"}); + m_indenter->format({{1, 2}}); + QCOMPARE(documentLines(), (std::vector{"foo(bar,", " \"foo\"", " \"bar\");"})); +} + +void ClangFormatTest::testFormatTemplateparameters() +{ + insertLines({"using Alias = Template"}); + m_indenter->format({{1, 3}}); + QCOMPARE(documentLines(), (std::vector{"using Alias = Template"})); +} + +void ClangFormatTest::testSortIncludes() +{ + insertLines({"#include \"b.h\"", + "#include \"a.h\"", + "", + "#include ", + "#include "}); + m_indenter->format({{1, 5}}); + QCOMPARE(documentLines(), (std::vector{ + "#include \"a.h\"", + "#include \"b.h\"", + "", + "#include ", + "#include "})); +} + +void ClangFormatTest::testChainedMemberFunctionCalls() +{ + insertLines({"S().func().func()", ".func();"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{"S().func().func()", " .func();"})); +} + +void ClangFormatTest::testCommentBlock() +{ + insertLines({"/****************************************************************************", + "**", + "** Copyright (C) 2021 The Qt Company Ltd.", + "** Contact: https://www.qt.io/licensing/", + "**", + "** This file is part of Qt Creator.", + "**", + "****************************************************************************/"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), (std::vector{ + "/****************************************************************************", + "**", + "** Copyright (C) 2021 The Qt Company Ltd.", + "** Contact: https://www.qt.io/licensing/", + "**", + "** This file is part of Qt Creator.", + "**", + "****************************************************************************/"})); +} + +} // namespace ClangFormat::Internal diff --git a/src/plugins/clangformat/tests/clangformat-test.h b/src/plugins/clangformat/tests/clangformat-test.h new file mode 100644 index 00000000000..e34a1491168 --- /dev/null +++ b/src/plugins/clangformat/tests/clangformat-test.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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 +#include + +QT_BEGIN_NAMESPACE +class QString; +class QTextCursor; +class QTextDocument; +QT_END_NAMESPACE + +namespace ClangFormat { +class ClangFormatBaseIndenter; + +namespace Internal { + +class ClangFormatTest : public QObject +{ + Q_OBJECT +public: + ClangFormatTest(); + ~ClangFormatTest(); + +private slots: + void testIndentBasicFile(); + void testIndentEmptyLine(); + void testIndentLambda(); + void testIndentNestedIfElse(); + void testIndentInitializerListInArguments(); + void testIndentLambdaWithReturnType(); + void testIndentFunctionArgumentLambdaWithNextLineScope(); + void testIndentScopeAsFunctionArgument(); + void testIndentInsideStructuredBinding(); + void testIndentMacrosWithoutSemicolon(); + void testIndentAfterSquareBracesInsideBraceInitialization(); + void testIndentStringLiteralContinuation(); + void testIndentTemplateparameters(); + void testNoExtraIndentAfterStatementInsideSquareBraces(); + void testNoExtraIndentAfterBraceInitialization(); + void testIndentMultipleEmptyLines(); + void testIndentEmptyLineAndKeepPreviousEmptyLines(); + void testIndentOnElectricCharacterButNotRemoveEmptyLinesBefore(); + void testIndentAfterExtraSpaceInpreviousLine(); + void testIndentEmptyLineInsideParentheses(); + void testIndentInsideIf(); + void testIndentInsideIf2(); + void testIndentInsideIf3(); + void testEmptyLineInInitializerList(); + void testIndentClosingBraceAfterComma(); + void testDoNotIndentClosingBraceAfterSemicolon(); + void testIndentAfterIf(); + void testIndentAfterElse(); + void testSameIndentAfterSecondNewLineAfterIf(); + void testIndentAfterNewLineInsideIfWithFunctionCall(); + void testSameIndentAfterSecondNewLineInsideIfWithFunctionCall(); + void testSameIndentAfterSecondNonEmptyNewLineInsideIfWithFunctionCall(); + void testSameIndentsOnNewLinesAfterComments(); + void testIndentAfterEmptyLineAfterAngledIncludeDirective(); + void testIndentAfterEmptyLineAfterQuotedIncludeDirective(); + void testIndentAfterLineComment(); + void testIndentAfterBlockComment(); + void testIndentAfterIfdef(); + void testIndentAfterEmptyLineInTheFileBeginning(); + void testIndentFunctionBodyButNotFormatBeforeIt(); + void testIndentAfterFunctionBodyAndNotFormatBefore(); + void testReformatToEmptyFunction(); + void testReformatToNonEmptyFunction(); + void testIndentClosingScopeAndFormatBeforeIt(); + void testDoNotFormatAfterTheFirstColon(); + void testOnlyIndentIncompleteStatementOnElectricalCharacter(); + void testIndentAndFormatCompleteStatementOnSemicolon(); + void testIndentAndFormatCompleteStatementOnClosingScope(); + void testOnlyIndentClosingParenthesis(); + void testEquallyIndentInsideParenthesis(); + void testFormatBasicFile(); + void testFormatEmptyLine(); + void testFormatLambda(); + void testFormatInitializerListInArguments(); + void testFormatFunctionArgumentLambdaWithScope(); + void testFormatScopeAsFunctionArgument(); + void testFormatStructuredBinding(); + void testFormatStringLiteralContinuation(); + void testFormatTemplateparameters(); + void testSortIncludes(); + void testChainedMemberFunctionCalls(); + void testCommentBlock(); + +private: + void insertLines(const std::vector &lines); + std::vector documentLines() const; + + QTextDocument * const m_doc; + QTextCursor * const m_cursor; + ClangFormatBaseIndenter * const m_indenter; + ClangFormatBaseIndenter * const m_extendedIndenter; +}; + +} // namespace Internal +} // namespace ClangFormat diff --git a/tests/unit/unittest/data/clangformat/.clang-format b/src/plugins/clangformat/tests/data/.clang-format similarity index 100% rename from tests/unit/unittest/data/clangformat/.clang-format rename to src/plugins/clangformat/tests/data/.clang-format diff --git a/tests/unit/unittest/CMakeLists.txt b/tests/unit/unittest/CMakeLists.txt index 9f2f8956cdf..3451bd7116e 100644 --- a/tests/unit/unittest/CMakeLists.txt +++ b/tests/unit/unittest/CMakeLists.txt @@ -466,21 +466,6 @@ extend_qtc_test(unittest cppprojectfile.cpp cppprojectfile.h ) -extend_qtc_test(unittest - SOURCES_PREFIX ../../../src/plugins/clangformat - CONDITION HAVE_LIBCLANG - DEPENDS ${CLANG_TOOLING_LIBS} - SOURCES - clangformatconstants.h - clangformatbaseindenter.cpp clangformatbaseindenter.h -) - -extend_qtc_test(unittest - CONDITION HAVE_LIBCLANG - SOURCES - clangformat-test.cpp -) - get_filename_component( QMLDOM_STANDALONE_CMAKELISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../../../qmldom_standalone/src/qmldom/standalone/" diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp deleted file mode 100644 index 9aec542edfd..00000000000 --- a/tests/unit/unittest/clangformat-test.cpp +++ /dev/null @@ -1,984 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "googletest.h" - -#include -#include - -#include - -namespace TextEditor { -class TabSettings -{}; -} // namespace TextEditor - -namespace { - -class ClangFormatIndenter : public ClangFormat::ClangFormatBaseIndenter -{ -public: - ClangFormatIndenter(QTextDocument *doc) - : ClangFormat::ClangFormatBaseIndenter(doc) - {} - - Utils::optional tabSettings() const override - { - return Utils::optional(); - } -}; - -class ClangFormatExtendedIndenter : public ClangFormatIndenter -{ -public: - ClangFormatExtendedIndenter(QTextDocument *doc) - : ClangFormatIndenter(doc) - {} - - bool formatWhileTyping() const override { return true; } -}; - -class ClangFormat : public ::testing::Test -{ -protected: - void SetUp() final - { - indenter.setFileName(Utils::FilePath::fromString(TESTDATA_DIR "/clangformat/test.cpp")); - extendedIndenter.setFileName( - Utils::FilePath::fromString(TESTDATA_DIR "/clangformat/test.cpp")); - } - - void insertLines(const std::vector &lines) - { - doc.clear(); - cursor.setPosition(0); - for (size_t lineNumber = 1; lineNumber <= lines.size(); ++lineNumber) { - if (lineNumber > 1) - cursor.insertBlock(); - - cursor.insertText(lines[lineNumber - 1]); - } - cursor.setPosition(0); - cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); - } - - std::vector documentLines() - { - std::vector result; - const int lines = doc.blockCount(); - result.reserve(static_cast(lines)); - for (int line = 0; line < lines; ++line) - result.push_back(doc.findBlockByNumber(line).text()); - - return result; - } - - QTextDocument doc; - ClangFormatIndenter indenter{&doc}; - ClangFormatExtendedIndenter extendedIndenter{&doc}; - QTextCursor cursor{&doc}; -}; - -// clang-format off -TEST_F(ClangFormat, IndentBasicFile) -{ - insertLines({"int main()", - "{", - "int a;", - "}"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("int main()", - "{", - " int a;", - "}")); -} - -TEST_F(ClangFormat, IndentEmptyLine) -{ - insertLines({"int main()", - "{", - "", - "}"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("int main()", - "{", - " ", - "}")); -} - -TEST_F(ClangFormat, IndentLambda) -{ - insertLines({"int b = foo([](){", - "", - "});"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("int b = foo([](){", - " ", - "});")); -} - -TEST_F(ClangFormat, IndentNestedIfElse) -{ - insertLines({"if (a)", - "if (b)", - "foo();", - "else", - "bar();", - "else", - "baz();"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), - ElementsAre("if (a)", - " if (b)", - " foo();", - " else", - " bar();", - "else", - " baz();")); -} - -TEST_F(ClangFormat, IndentInitializerListInArguments) -{ - insertLines({"foo(arg1,", - "args,", - "{1, 2});"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("foo(arg1,", - " args,", - " {1, 2});")); -} - -TEST_F(ClangFormat, IndentLambdaWithReturnType) -{ - insertLines({"{", - "auto lambda = []() -> bool {", - "", - "};", - "}"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), - ElementsAre("{", - " auto lambda = []() -> bool {", - " ", - " };", - "}")); -} - -TEST_F(ClangFormat, ClangFormatIndentFunctionArgumentLambdaWithNextLineScope) -{ - insertLines({"foo([]()", - "{", - "", - "});"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), - ElementsAre("foo([]()", - " {", - " ", - " });")); -} - -TEST_F(ClangFormat, IndentScopeAsFunctionArgument) -{ - insertLines({"foo(", - "{", - "", - "});"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), - ElementsAre("foo(", - " {", - " ", - " });")); -} - -TEST_F(ClangFormat, IndentInsideStructuredBinding) -{ - insertLines({"auto [a,", - "b] = c;"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("auto [a,", - " b] = c;")); -} - -TEST_F(ClangFormat, IndentMacrosWithoutSemicolon) -{ - insertLines({"void test()", - "{", - "ASSERT(1);", - "ASSERT(2)", - "ASSERT(3)", - "ASSERT(4);", - "ASSERT(5)", - "}"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("void test()", - "{", - " ASSERT(1);", - " ASSERT(2)", - " ASSERT(3)", - " ASSERT(4);", - " ASSERT(5)", - "}")); -} - -TEST_F(ClangFormat, IndentAfterSquareBracesInsideBraceInitialization) -{ - insertLines({"int foo() {", - "char a = char{b[0]};", - "int c;", - "}"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("int foo() {", - " char a = char{b[0]};", - " int c;", - "}")); -} - -TEST_F(ClangFormat, IndentStringLiteralContinuation) -{ - insertLines({"foo(bar, \"foo\"", - "\"bar\");"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("foo(bar, \"foo\"", - " \"bar\");")); -} - -TEST_F(ClangFormat, IndentTemplateparameters) -{ - insertLines({"using Alias = Template"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("using Alias = Template")); -} - -TEST_F(ClangFormat, NoExtraIndentAfterStatementInsideSquareBraces) -{ - insertLines({"{", - " x[y=z];", - " int a;", - "}"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("{", - " x[y=z];", - " int a;", - "}")); -} - -TEST_F(ClangFormat, NoExtraIndentAfterBraceInitialization) -{ - insertLines({"int j{i?5:10};", - "return 0;"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("int j{i?5:10};", - "return 0;")); -} - -TEST_F(ClangFormat, IndentMultipleEmptyLines) -{ - insertLines({"{", - "", - "", - "", - "}"}); - - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("{", - " ", - " ", - " ", - "}")); -} - -TEST_F(ClangFormat, IndentEmptyLineAndKeepPreviousEmptyLines) -{ - insertLines({"{", - " ", - " ", - "", - "}"}); - - indenter.indentBlock(doc.findBlockByNumber(3), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("{", - " ", - " ", - " ", - "}")); -} - -TEST_F(ClangFormat, IndentOnElectricCharacterButNotRemoveEmptyLinesBefore) -{ - insertLines({"{", - " ", - " ", - "if ()", - "}"}); - - indenter.indentBlock(doc.findBlockByNumber(3), '(', TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("{", - " ", - " ", - " if ()", - "}")); -} - -TEST_F(ClangFormat, IndentAfterExtraSpaceInpreviousLine) -{ - insertLines({"if (a ", - "&& b)"}); - - indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("if (a", - " && b)")); -} - -TEST_F(ClangFormat, IndentEmptyLineInsideParantheses) -{ - insertLines({"if (a ", - "", - " && b)"}); - - indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("if (a", - " ", - " && b)")); -} - -TEST_F(ClangFormat, IndentInsideIf) -{ - insertLines({"if (a && b", - ")"}); - - indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("if (a && b", - " )")); -} - -TEST_F(ClangFormat, IndentInsideIf2) -{ - insertLines({"if (a && b &&", - ")"}); - - indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("if (a && b &&", - " )")); -} - -TEST_F(ClangFormat, IndentInsideIf3) -{ - insertLines({"if (a || b", - ")"}); - - indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("if (a || b", - " )")); -} - -TEST_F(ClangFormat, EmptyLineInInitializerList) -{ - insertLines({"Bar foo{a,", - "", - "};"}); - - indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("Bar foo{a,", - " ", - "};")); -} - -TEST_F(ClangFormat, IndentClosingBraceAfterComma) -{ - insertLines({"Bar foo{a,", - "}"}); - - indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("Bar foo{a,", - " }")); -} - -TEST_F(ClangFormat, DoNotIndentClosingBraceAfterSemicolon) -{ - insertLines({"{", - " a;" - "}"}); - - indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("{", - " a;" - "}")); -} - -TEST_F(ClangFormat, IndentAfterIf) -{ - insertLines({"if (a)", - ""}); - - indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("if (a)", - " ")); -} - -TEST_F(ClangFormat, IndentAfterElse) -{ - insertLines({"if (a)", - " foo();", - "else", - ""}); - indenter.indentBlock(doc.findBlockByNumber(3), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("if (a)", - " foo();", - "else", - " ")); -} - -TEST_F(ClangFormat, SameIndentAfterSecondNewLineAfterIf) -{ - insertLines({"if (a)", - " ", - ""}); - - indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("if (a)", - " ", - " ")); -} - -TEST_F(ClangFormat, IndentAfterNewLineInsideIfWithFunctionCall) -{ - insertLines({"if (foo()", - ")"}); - - indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("if (foo()", - " )")); -} - -TEST_F(ClangFormat, SameIndentAfterSecondNewLineInsideIfWithFunctionCall) -{ - insertLines({"if (foo()", - " ", - ")"}); - - indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("if (foo()", - " ", - " )")); -} - -TEST_F(ClangFormat, SameIndentAfterSecondNonEmptyNewLineInsideIfWithFunctionCall) -{ - insertLines({"if (foo()", - " ", - "bar)"}); - - indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("if (foo()", - " ", - " bar)")); -} - -TEST_F(ClangFormat, SameIndentsOnNewLinesAfterComments) -{ - insertLines({"namespace {} //comment", - "", - ""}); - - indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("namespace {} //comment", - "", - "")); -} - -TEST_F(ClangFormat, IndentAfterEmptyLineAfterAngledIncludeDirective) -{ - insertLines({"#include ", - "", - "using namespace std;"}); - - indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("#include ", - "", - "using namespace std;")); -} - -TEST_F(ClangFormat, IndentAfterEmptyLineAfterQuotedIncludeDirective) -{ - insertLines({"#include \"foo.h\"", - "", - "using namespace std;"}); - - indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("#include \"foo.h\"", - "", - "using namespace std;")); -} - -TEST_F(ClangFormat, IndentAfterLineComment) -{ - insertLines({"int foo()", - "{", - " // Comment", - " ", - " if (", - "}"}); - - indenter.indentBlock(doc.findBlockByNumber(4), '(', TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("int foo()", - "{", - " // Comment", - " ", - " if (", - "}")); -} - -TEST_F(ClangFormat, IndentAfterBlockComment) -{ - insertLines({"int foo()", - "{", - " bar(); /* Comment */", - " ", - " if (", - "}"}); - - indenter.indentBlock(doc.findBlockByNumber(4), '(', TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("int foo()", - "{", - " bar(); /* Comment */", - " ", - " if (", - "}")); -} - -TEST_F(ClangFormat, IndentAfterIfdef) -{ - insertLines({"int foo()", - "{", - "#ifdef FOO", - "#endif", - " ", - " if (", - "}"}); - - indenter.indentBlock(doc.findBlockByNumber(5), '(', TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("int foo()", - "{", - "#ifdef FOO", - "#endif", - " ", - " if (", - "}")); -} - -TEST_F(ClangFormat, IndentAfterEmptyLineInTheFileBeginning) -{ - insertLines({"", - "void foo()"}); - - indenter.indentBlock(doc.findBlockByNumber(1), ')', TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("", - "void foo()")); -} - -TEST_F(ClangFormat, IndentFunctionBodyButNotFormatBeforeIt) -{ - insertLines({"int foo(int a, int b,", - " int c, int d", - " ) {", - "", - "}"}); - - extendedIndenter.indentBlock(doc.findBlockByNumber(3), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b,", - " int c, int d", - " ) {", - " ", - "}")); -} - -TEST_F(ClangFormat, IndentAfterFunctionBodyAndNotFormatBefore) -{ - insertLines({"int foo(int a, int b, int c, int d)", - "{", - " ", - "}"}); - - extendedIndenter.indentBlock(doc.findBlockByNumber(3), - QChar::Null, - TextEditor::TabSettings(), - doc.characterCount() - 3); - - ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b, int c, int d)", - "{", - " ", - "}")); -} - -TEST_F(ClangFormat, ReformatToEmptyFunction) -{ - insertLines({"int foo(int a, int b, int c, int d)", - "{", - " ", - "}"}); - - extendedIndenter.indentBlock(doc.findBlockByNumber(3), '}', TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b, int c, int d) {}")); -} - -TEST_F(ClangFormat, ReformatToNonEmptyFunction) -{ - insertLines({"int foo(int a, int b) {", - "", - "}"}); - - extendedIndenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b) {", - " ", - "}")); -} - -TEST_F(ClangFormat, IndentClosingScopeAndFormatBeforeIt) -{ - insertLines({"if(a && b", - " &&c && d", - " ) {", - "", - "}"}); - - extendedIndenter.indentBlock(doc.findBlockByNumber(4), '}', TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("if (a && b && c && d) {", - "}")); -} - -TEST_F(ClangFormat, DoNotFormatAfterTheFirstColon) -{ - insertLines({"{", - " Qt:", - "}"}); - - extendedIndenter.indentBlock(doc.findBlockByNumber(1), ':', TextEditor::TabSettings(), 9); - - ASSERT_THAT(documentLines(), ElementsAre("{", - " Qt:", - "}")); -} - -TEST_F(ClangFormat, OnlyIndentIncompleteStatementOnElectricalCharacter) -{ - insertLines({"{bar();", - "foo()", - "}"}); - - extendedIndenter.indentBlock(doc.findBlockByNumber(1), '(', TextEditor::TabSettings(), 12); - - ASSERT_THAT(documentLines(), ElementsAre("{bar();", - " foo()", - "}")); -} - -TEST_F(ClangFormat, IndentAndFormatCompleteStatementOnSemicolon) -{ - insertLines({"{bar();", - "foo();", - "}"}); - - extendedIndenter.indentBlock(doc.findBlockByNumber(1), ';', TextEditor::TabSettings(), 14); - - ASSERT_THAT(documentLines(), ElementsAre("{", - " bar();", - " foo();", - "}")); -} - -TEST_F(ClangFormat, IndentAndFormatCompleteStatementOnClosingScope) -{ - insertLines({"{bar();", - "foo();", - "}"}); - - extendedIndenter.indentBlock(doc.findBlockByNumber(1), '}', TextEditor::TabSettings(), 16); - - ASSERT_THAT(documentLines(), ElementsAre("{", - " bar();", - " foo();", - "}")); -} - -TEST_F(ClangFormat, OnlyIndentClosingParenthesis) -{ - insertLines({"foo(a,", - " ", - ")"}); - - extendedIndenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(documentLines(), ElementsAre("foo(a,", - " ", - " )")); -} - -TEST_F(ClangFormat, EquallyIndentInsideParenthesis) -{ - insertLines({"if (a", - ")"}); - extendedIndenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); - auto linesAfterFirstLineBreak = documentLines(); - insertLines({"if (a", - " ", - ")"}); - extendedIndenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); - - ASSERT_THAT(linesAfterFirstLineBreak, ElementsAre("if (a", - " )")); - ASSERT_THAT(documentLines(), ElementsAre("if (a", - " ", - " )")); -} - -TEST_F(ClangFormat, FormatBasicFile) -{ - insertLines({"int main()", - "{", - "int a;", - "}"}); - - indenter.format({{1, 4}}); - - ASSERT_THAT(documentLines(), ElementsAre("int main()", - "{", - " int a;", - "}")); -} - -TEST_F(ClangFormat, FormatEmptyLine) -{ - insertLines({"int main()", - "{", - "", - "}"}); - - indenter.format({{1, 4}}); - - ASSERT_THAT(documentLines(), ElementsAre("int main() {}")); -} - -TEST_F(ClangFormat, FormatLambda) -{ - insertLines({"int b = foo([](){", - "", - "});"}); - - indenter.format({{1, 3}}); - - ASSERT_THAT(documentLines(), ElementsAre("int b = foo([]() {", - "", - "});")); -} - -TEST_F(ClangFormat, FormatInitializerListInArguments) -{ - insertLines({"foo(arg1,", - "args,", - "{1, 2});"}); - - indenter.format({{1, 3}}); - - ASSERT_THAT(documentLines(), ElementsAre("foo(arg1, args, {1, 2});")); -} - -TEST_F(ClangFormat, FormatFunctionArgumentLambdaWithScope) -{ - insertLines({"foo([]()", - "{", - "", - "});"}); - - indenter.format({{1, 4}}); - - ASSERT_THAT(documentLines(), - ElementsAre("foo([]() {", - "", - "});")); -} - -TEST_F(ClangFormat, FormatScopeAsFunctionArgument) -{ - insertLines({"foo(", - "{", - "", - "});"}); - - indenter.format({{1, 4}}); - - ASSERT_THAT(documentLines(), - ElementsAre("foo({", - "", - "});")); -} - -TEST_F(ClangFormat, FormatStructuredBinding) -{ - insertLines({"auto [a,", - "b] = c;"}); - - indenter.format({{1, 2}}); - - ASSERT_THAT(documentLines(), ElementsAre("auto [a, b] = c;")); -} - -TEST_F(ClangFormat, FormatStringLiteralContinuation) -{ - insertLines({"foo(bar, \"foo\"", - "\"bar\");"}); - - indenter.format({{1, 2}}); - - ASSERT_THAT(documentLines(), ElementsAre("foo(bar,", - " \"foo\"", - " \"bar\");")); -} - -TEST_F(ClangFormat, FormatTemplateparameters) -{ - insertLines({"using Alias = Template"}); - - indenter.format({{1, 3}}); - - ASSERT_THAT(documentLines(), ElementsAre("using Alias = Template")); -} - -TEST_F(ClangFormat, SortIncludes) -{ - insertLines({"#include \"b.h\"", - "#include \"a.h\"", - "", - "#include ", - "#include "}); - - indenter.format({{1, 5}}); - - ASSERT_THAT(documentLines(), ElementsAre("#include \"a.h\"", - "#include \"b.h\"", - "", - "#include ", - "#include ")); -} - -TEST_F(ClangFormat, ChainedMemberFunctionCalls) -{ - insertLines({"S().func().func()", - ".func();"}); - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - ASSERT_THAT(documentLines(), ElementsAre("S().func().func()", - " .func();")); -} - -TEST_F(ClangFormat, CommentBlock) -{ - insertLines({"/****************************************************************************", - "**", - "** Copyright (C) 2021 The Qt Company Ltd.", - "** Contact: https://www.qt.io/licensing/", - "**", - "** This file is part of Qt Creator.", - "**", - "****************************************************************************/"}); - indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - ASSERT_THAT(documentLines(), ElementsAre( - "/****************************************************************************", - "**", - "** Copyright (C) 2021 The Qt Company Ltd.", - "** Contact: https://www.qt.io/licensing/", - "**", - "** This file is part of Qt Creator.", - "**", - "****************************************************************************/")); -} - -// clang-format on - -} // namespace diff --git a/tests/unit/unittest/creator_dependency.pri b/tests/unit/unittest/creator_dependency.pri index 6b4eced4aac..a66989b20bd 100644 --- a/tests/unit/unittest/creator_dependency.pri +++ b/tests/unit/unittest/creator_dependency.pri @@ -13,7 +13,6 @@ include($$PWD/../../../src/plugins/clangtools/clangtoolsunittestfiles.pri) include($$PWD/../../../src/shared/clang/clang_defines.pri) include($$PWD/../../../src/tools/clangbackend/source/clangbackendclangipc-source.pri) include($$PWD/../../../src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri) -!isEmpty(CLANGFORMAT_LIBS): include($$PWD/../../../src/plugins/clangformat/clangformat-source.pri) } else { DEFINES += CLANG_VERSION=\\\"6.0.0\\\" DEFINES += "\"CLANG_INCLUDE_DIR=\\\"/usr/include\\\"\"" diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 3369cdfd693..58677b4263c 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -170,10 +170,6 @@ SOURCES += \ gtest-llvm-printing.cpp \ } -!isEmpty(CLANGFORMAT_LIBS) { - SOURCES += clangformat-test.cpp -} - !isEmpty(GOOGLEBENCHMARK_DIR):exists($$GOOGLEBENCHMARK_DIR) { SOURCES += \ smallstring-benchmark.cpp diff --git a/tests/unit/unittest/unittest.qbs b/tests/unit/unittest/unittest.qbs index 686f167029b..83c6260c5a9 100644 --- a/tests/unit/unittest/unittest.qbs +++ b/tests/unit/unittest/unittest.qbs @@ -291,14 +291,6 @@ Project { ] } - Group { - name: "ClangFormat tests" - condition: libclang.present - && libclang.llvmFormattingLibs.length - && (!qbs.targetOS.contains("windows") || libclang.llvmBuildModeMatches) - files: "clangformat-test.cpp" - } - Group { name: "benchmark test" condition: benchmark.present @@ -486,19 +478,6 @@ Project { ] } - Group { - name: "sources from ClangFormat" - prefix: "../../../src/plugins/clangformat/" - condition: libclang.present - && libclang.llvmFormattingLibs.length - && (!qbs.targetOS.contains("windows") || libclang.llvmBuildModeMatches) - files: [ - "clangformatbaseindenter.cpp", - "clangformatbaseindenter.h", - "clangformatconstants.h", - ] - } - Group { name: "sources from Debugger" prefix: "../../../src/plugins/debugger/analyzer/"