blob: e5dee5c957e7abf5e7d69a350b922c55b448fe6f [file] [log] [blame]
//===-- 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