forked from OSchip/llvm-project
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
|