309 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			309 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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
 |