321 lines · cpp
1//===-- FormatTests.cpp - Automatic code formatting tests -----------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Format.h"10#include "Annotations.h"11#include "SourceCode.h"12#include "clang/Format/Format.h"13#include "clang/Tooling/Core/Replacement.h"14#include "llvm/Support/Error.h"15#include "gmock/gmock.h"16#include "gtest/gtest.h"17 18namespace clang {19namespace clangd {20namespace {21 22std::string afterTyped(llvm::StringRef CodeWithCursor, llvm::StringRef Typed,23 clang::format::FormatStyle Style) {24 Annotations Code(CodeWithCursor);25 unsigned Cursor = llvm::cantFail(positionToOffset(Code.code(), Code.point()));26 auto Changes = formatIncremental(Code.code(), Cursor, Typed, Style);27 tooling::Replacements Merged;28 for (const auto& R : Changes)29 if (llvm::Error E = Merged.add(R))30 ADD_FAILURE() << llvm::toString(std::move(E));31 auto NewCode = tooling::applyAllReplacements(Code.code(), Merged);32 EXPECT_TRUE(bool(NewCode))33 << "Bad replacements: " << llvm::toString(NewCode.takeError());34 NewCode->insert(transformCursorPosition(Cursor, Changes), "^");35 return *NewCode;36}37 38// We can't pass raw strings directly to EXPECT_EQ because of gcc bugs.39void expectAfterNewline(const char *Before, const char *After,40 format::FormatStyle Style = format::getGoogleStyle(41 format::FormatStyle::LK_Cpp)) {42 EXPECT_EQ(After, afterTyped(Before, "\n", Style)) << Before;43}44void expectAfter(const char *Typed, const char *Before, const char *After,45 format::FormatStyle Style =46 format::getGoogleStyle(format::FormatStyle::LK_Cpp)) {47 EXPECT_EQ(After, afterTyped(Before, Typed, Style)) << Before;48}49 50TEST(FormatIncremental, SplitComment) {51 expectAfterNewline(R"cpp(52// this comment was53^split54)cpp",55 R"cpp(56// this comment was57// ^split58)cpp");59 60 expectAfterNewline(R"cpp(61// trailing whitespace is not a split62^ 63)cpp",64 R"cpp(65// trailing whitespace is not a split66^67)cpp");68 69 expectAfterNewline(R"cpp(70// splitting a71^72// multiline comment73)cpp",74 R"cpp(75// splitting a76// ^77// multiline comment78)cpp");79 80 expectAfterNewline(R"cpp(81// extra 82 ^ whitespace83)cpp",84 R"cpp(85// extra86// ^whitespace87)cpp");88 89 expectAfterNewline(R"cpp(90/// triple91^slash92)cpp",93 R"cpp(94/// triple95/// ^slash96)cpp");97 98 expectAfterNewline(R"cpp(99/// editor continuation100//^101)cpp",102 R"cpp(103/// editor continuation104/// ^105)cpp");106 107 expectAfterNewline(R"cpp(108// break before109^ // slashes110)cpp",111 R"cpp(112// break before113^// slashes114)cpp");115 116 117 expectAfterNewline(R"cpp(118int x; // aligned119^comment120)cpp",121 R"cpp(122int x; // aligned123 // ^comment124)cpp");125 126 // Fixed bug: the second line of the aligned comment shouldn't be "attached"127 // to the cursor and outdented.128 expectAfterNewline(R"cpp(129void foo() {130 if (x)131 return; // All spelled tokens are accounted for.132 // that takes two lines133 ^134}135)cpp",136 R"cpp(137void foo() {138 if (x)139 return; // All spelled tokens are accounted for.140 // that takes two lines141 ^142}143)cpp");144 145 // Handle tab character in leading indentation146 format::FormatStyle TabStyle =147 format::getGoogleStyle(format::FormatStyle::LK_Cpp);148 TabStyle.UseTab = format::FormatStyle::UT_Always;149 TabStyle.TabWidth = 4;150 TabStyle.IndentWidth = 4;151 // Do not use raw strings, otherwise '\t' will be interpreted literally.152 expectAfterNewline("void foo() {\n\t// this comment was\n^split\n}\n",153 "void foo() {\n\t// this comment was\n\t// ^split\n}\n",154 TabStyle);155}156 157TEST(FormatIncremental, Indentation) {158 expectAfterNewline(R"cpp(159void foo() {160 if (bar)161^162)cpp",163 R"cpp(164void foo() {165 if (bar)166 ^167)cpp");168 169 expectAfterNewline(R"cpp(170void foo() {171 bar(baz(172^173)cpp",174 R"cpp(175void foo() {176 bar(baz(177 ^178)cpp");179 180 expectAfterNewline(R"cpp(181void foo() {182^}183)cpp",184 R"cpp(185void foo() {186 ^187}188)cpp");189 190 expectAfterNewline(R"cpp(191class X {192protected:193^194)cpp",195 R"cpp(196class X {197 protected:198 ^199)cpp");200 201// Mismatched brackets (1)202 expectAfterNewline(R"cpp(203void foo() {204 foo{bar(205^}206}207)cpp",208 R"cpp(209void foo() {210 foo {211 bar(212 ^}213}214)cpp");215// Mismatched brackets (2)216 expectAfterNewline(R"cpp(217void foo() {218 foo{bar(219^text}220}221)cpp",222 R"cpp(223void foo() {224 foo {225 bar(226 ^text}227}228)cpp");229// Matched brackets230 expectAfterNewline(R"cpp(231void foo() {232 foo{bar(233^)234}235)cpp",236 R"cpp(237void foo() {238 foo {239 bar(240 ^)241}242)cpp");243}244 245TEST(FormatIncremental, FormatPreviousLine) {246 expectAfterNewline(R"cpp(247void foo() {248 untouched( );249int x=2;250^251)cpp",252 R"cpp(253void foo() {254 untouched( );255 int x = 2;256 ^257)cpp");258 259 expectAfterNewline(R"cpp(260int x=untouched( );261auto L = []{return;return;};262^263)cpp",264 R"cpp(265int x=untouched( );266auto L = [] {267 return;268 return;269};270^271)cpp");272}273 274TEST(FormatIncremental, Annoyances) {275 // Don't remove newlines the user typed!276 expectAfterNewline(R"cpp(277int x(){278 279 280^281}282)cpp",283 R"cpp(284int x(){285 286 287 ^288}289)cpp");290 // FIXME: we should not remove newlines here, either.291 expectAfterNewline(R"cpp(292class x{293 public:294 295^296}297)cpp",298 R"cpp(299class x{300 public:301 ^302}303)cpp");304}305 306TEST(FormatIncremental, FormatBrace) {307 expectAfter("}", R"cpp(308vector<int> x= {309 1,310 2,311 3}^312)cpp",313 R"cpp(314vector<int> x = {1, 2, 3}^315)cpp");316}317 318} // namespace319} // namespace clangd320} // namespace clang321