|  | //===-- FormatTests.cpp - Automatic code formatting tests -----------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "Format.h" | 
|  | #include "Annotations.h" | 
|  | #include "SourceCode.h" | 
|  | #include "TestFS.h" | 
|  | #include "clang/Format/Format.h" | 
|  | #include "clang/Tooling/Core/Replacement.h" | 
|  | #include "llvm/Support/Error.h" | 
|  | #include "gmock/gmock.h" | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | namespace clang { | 
|  | namespace clangd { | 
|  | namespace { | 
|  |  | 
|  | std::string afterTyped(llvm::StringRef CodeWithCursor, | 
|  | llvm::StringRef Typed) { | 
|  | Annotations Code(CodeWithCursor); | 
|  | unsigned Cursor = llvm::cantFail(positionToOffset(Code.code(), Code.point())); | 
|  | auto Changes = | 
|  | formatIncremental(Code.code(), Cursor, Typed, | 
|  | format::getGoogleStyle(format::FormatStyle::LK_Cpp)); | 
|  | tooling::Replacements Merged; | 
|  | for (const auto& R : Changes) | 
|  | if (llvm::Error E = Merged.add(R)) | 
|  | ADD_FAILURE() << llvm::toString(std::move(E)); | 
|  | auto NewCode = tooling::applyAllReplacements(Code.code(), Merged); | 
|  | EXPECT_TRUE(bool(NewCode)) | 
|  | << "Bad replacements: " << llvm::toString(NewCode.takeError()); | 
|  | NewCode->insert(transformCursorPosition(Cursor, Changes), "^"); | 
|  | return *NewCode; | 
|  | } | 
|  |  | 
|  | // We can't pass raw strings directly to EXPECT_EQ because of gcc bugs. | 
|  | void expectAfterNewline(const char *Before, const char *After) { | 
|  | EXPECT_EQ(After, afterTyped(Before, "\n")) << Before; | 
|  | } | 
|  | void expectAfter(const char *Typed, const char *Before, const char *After) { | 
|  | EXPECT_EQ(After, afterTyped(Before, Typed)) << Before; | 
|  | } | 
|  |  | 
|  | TEST(FormatIncremental, SplitComment) { | 
|  | expectAfterNewline(R"cpp( | 
|  | // this comment was | 
|  | ^split | 
|  | )cpp", | 
|  | R"cpp( | 
|  | // this comment was | 
|  | // ^split | 
|  | )cpp"); | 
|  |  | 
|  | expectAfterNewline(R"cpp( | 
|  | // trailing whitespace is not a split | 
|  | ^ | 
|  | )cpp", | 
|  | R"cpp( | 
|  | // trailing whitespace is not a split | 
|  | ^ | 
|  | )cpp"); | 
|  |  | 
|  | expectAfterNewline(R"cpp( | 
|  | // splitting a | 
|  | ^ | 
|  | // multiline comment | 
|  | )cpp", | 
|  | R"cpp( | 
|  | // splitting a | 
|  | // ^ | 
|  | // multiline comment | 
|  | )cpp"); | 
|  |  | 
|  | expectAfterNewline(R"cpp( | 
|  | // extra | 
|  | ^     whitespace | 
|  | )cpp", | 
|  | R"cpp( | 
|  | // extra | 
|  | // ^whitespace | 
|  | )cpp"); | 
|  |  | 
|  | expectAfterNewline(R"cpp( | 
|  | /// triple | 
|  | ^slash | 
|  | )cpp", | 
|  | R"cpp( | 
|  | /// triple | 
|  | /// ^slash | 
|  | )cpp"); | 
|  |  | 
|  | expectAfterNewline(R"cpp( | 
|  | /// editor continuation | 
|  | //^ | 
|  | )cpp", | 
|  | R"cpp( | 
|  | /// editor continuation | 
|  | /// ^ | 
|  | )cpp"); | 
|  |  | 
|  | expectAfterNewline(R"cpp( | 
|  | // break before | 
|  | ^ // slashes | 
|  | )cpp", | 
|  | R"cpp( | 
|  | // break before | 
|  | ^// slashes | 
|  | )cpp"); | 
|  |  | 
|  |  | 
|  | expectAfterNewline(R"cpp( | 
|  | int x;  // aligned | 
|  | ^comment | 
|  | )cpp", | 
|  | R"cpp( | 
|  | int x;  // aligned | 
|  | // ^comment | 
|  | )cpp"); | 
|  |  | 
|  | // Fixed bug: the second line of the aligned comment shouldn't be "attached" | 
|  | // to the cursor and outdented. | 
|  | expectAfterNewline(R"cpp( | 
|  | void foo() { | 
|  | if (x) | 
|  | return; // All spelled tokens are accounted for. | 
|  | // that takes two lines | 
|  | ^ | 
|  | } | 
|  | )cpp", | 
|  | R"cpp( | 
|  | void foo() { | 
|  | if (x) | 
|  | return;  // All spelled tokens are accounted for. | 
|  | // that takes two lines | 
|  | ^ | 
|  | } | 
|  | )cpp"); | 
|  | } | 
|  |  | 
|  | TEST(FormatIncremental, Indentation) { | 
|  | expectAfterNewline(R"cpp( | 
|  | void foo() { | 
|  | if (bar) | 
|  | ^ | 
|  | )cpp", | 
|  | R"cpp( | 
|  | void foo() { | 
|  | if (bar) | 
|  | ^ | 
|  | )cpp"); | 
|  |  | 
|  | expectAfterNewline(R"cpp( | 
|  | void foo() { | 
|  | bar(baz( | 
|  | ^ | 
|  | )cpp", | 
|  | R"cpp( | 
|  | void foo() { | 
|  | bar(baz( | 
|  | ^ | 
|  | )cpp"); | 
|  |  | 
|  | expectAfterNewline(R"cpp( | 
|  | void foo() { | 
|  | ^} | 
|  | )cpp", | 
|  | R"cpp( | 
|  | void foo() { | 
|  | ^ | 
|  | } | 
|  | )cpp"); | 
|  |  | 
|  | expectAfterNewline(R"cpp( | 
|  | class X { | 
|  | protected: | 
|  | ^ | 
|  | )cpp", | 
|  | R"cpp( | 
|  | class X { | 
|  | protected: | 
|  | ^ | 
|  | )cpp"); | 
|  |  | 
|  | // Mismatched brackets (1) | 
|  | expectAfterNewline(R"cpp( | 
|  | void foo() { | 
|  | foo{bar( | 
|  | ^} | 
|  | } | 
|  | )cpp", | 
|  | R"cpp( | 
|  | void foo() { | 
|  | foo { | 
|  | bar( | 
|  | ^} | 
|  | } | 
|  | )cpp"); | 
|  | // Mismatched brackets (2) | 
|  | expectAfterNewline(R"cpp( | 
|  | void foo() { | 
|  | foo{bar( | 
|  | ^text} | 
|  | } | 
|  | )cpp", | 
|  | R"cpp( | 
|  | void foo() { | 
|  | foo { | 
|  | bar( | 
|  | ^text} | 
|  | } | 
|  | )cpp"); | 
|  | // Matched brackets | 
|  | expectAfterNewline(R"cpp( | 
|  | void foo() { | 
|  | foo{bar( | 
|  | ^) | 
|  | } | 
|  | )cpp", | 
|  | R"cpp( | 
|  | void foo() { | 
|  | foo { | 
|  | bar( | 
|  | ^) | 
|  | } | 
|  | )cpp"); | 
|  | } | 
|  |  | 
|  | TEST(FormatIncremental, FormatPreviousLine) { | 
|  | expectAfterNewline(R"cpp( | 
|  | void foo() { | 
|  | untouched( ); | 
|  | int x=2; | 
|  | ^ | 
|  | )cpp", | 
|  | R"cpp( | 
|  | void foo() { | 
|  | untouched( ); | 
|  | int x = 2; | 
|  | ^ | 
|  | )cpp"); | 
|  |  | 
|  | expectAfterNewline(R"cpp( | 
|  | int x=untouched( ); | 
|  | auto L = []{return;return;}; | 
|  | ^ | 
|  | )cpp", | 
|  | R"cpp( | 
|  | int x=untouched( ); | 
|  | auto L = [] { | 
|  | return; | 
|  | return; | 
|  | }; | 
|  | ^ | 
|  | )cpp"); | 
|  | } | 
|  |  | 
|  | TEST(FormatIncremental, Annoyances) { | 
|  | // Don't remove newlines the user typed! | 
|  | expectAfterNewline(R"cpp( | 
|  | int x(){ | 
|  |  | 
|  |  | 
|  | ^ | 
|  | } | 
|  | )cpp", | 
|  | R"cpp( | 
|  | int x(){ | 
|  |  | 
|  |  | 
|  | ^ | 
|  | } | 
|  | )cpp"); | 
|  | // FIXME: we should not remove newlines here, either. | 
|  | expectAfterNewline(R"cpp( | 
|  | class x{ | 
|  | public: | 
|  |  | 
|  | ^ | 
|  | } | 
|  | )cpp", | 
|  | R"cpp( | 
|  | class x{ | 
|  | public: | 
|  | ^ | 
|  | } | 
|  | )cpp"); | 
|  | } | 
|  |  | 
|  | TEST(FormatIncremental, FormatBrace) { | 
|  | expectAfter("}", R"cpp( | 
|  | vector<int> x= { | 
|  | 1, | 
|  | 2, | 
|  | 3}^ | 
|  | )cpp", | 
|  | R"cpp( | 
|  | vector<int> x = {1, 2, 3}^ | 
|  | )cpp"); | 
|  | } | 
|  |  | 
|  | } // namespace | 
|  | } // namespace clangd | 
|  | } // namespace clang |