CleanupTest.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. //===- unittest/Format/CleanupTest.cpp - Code cleanup unit 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-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "clang/Format/Format.h"
  9. #include "../Tooling/ReplacementTest.h"
  10. #include "../Tooling/RewriterTestContext.h"
  11. #include "clang/Tooling/Core/Replacement.h"
  12. #include "gtest/gtest.h"
  13. using clang::tooling::ReplacementTest;
  14. using clang::tooling::toReplacements;
  15. namespace clang {
  16. namespace format {
  17. namespace {
  18. class CleanupTest : public ::testing::Test {
  19. protected:
  20. std::string cleanup(llvm::StringRef Code,
  21. const std::vector<tooling::Range> &Ranges,
  22. const FormatStyle &Style = getLLVMStyle()) {
  23. tooling::Replacements Replaces = format::cleanup(Style, Code, Ranges);
  24. auto Result = applyAllReplacements(Code, Replaces);
  25. EXPECT_TRUE(static_cast<bool>(Result));
  26. return *Result;
  27. }
  28. // Returns code after cleanup around \p Offsets.
  29. std::string cleanupAroundOffsets(llvm::ArrayRef<unsigned> Offsets,
  30. llvm::StringRef Code,
  31. const FormatStyle &Style = getLLVMStyle()) {
  32. std::vector<tooling::Range> Ranges;
  33. for (auto Offset : Offsets)
  34. Ranges.push_back(tooling::Range(Offset, 0));
  35. return cleanup(Code, Ranges, Style);
  36. }
  37. };
  38. TEST_F(CleanupTest, DeleteEmptyNamespaces) {
  39. std::string Code = "namespace A {\n"
  40. "namespace B {\n"
  41. "} // namespace B\n"
  42. "} // namespace A\n\n"
  43. "namespace C {\n"
  44. "namespace D { int i; }\n"
  45. "inline namespace E { namespace { } }\n"
  46. "}";
  47. std::string Expected = "\n\n\n\n\nnamespace C {\n"
  48. "namespace D { int i; }\n \n"
  49. "}";
  50. EXPECT_EQ(Expected, cleanupAroundOffsets({28, 91, 132}, Code));
  51. }
  52. TEST_F(CleanupTest, NamespaceWithSyntaxError) {
  53. std::string Code = "namespace A {\n"
  54. "namespace B {\n" // missing r_brace
  55. "} // namespace A\n\n"
  56. "namespace C {\n"
  57. "namespace D int i; }\n"
  58. "inline namespace E { namespace { } }\n"
  59. "}";
  60. std::string Expected = "namespace A {\n"
  61. "\n\n\nnamespace C {\n"
  62. "namespace D int i; }\n \n"
  63. "}";
  64. std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
  65. EXPECT_EQ(Expected, cleanup(Code, Ranges));
  66. }
  67. TEST_F(CleanupTest, EmptyNamespaceNotAffected) {
  68. std::string Code = "namespace A {\n\n"
  69. "namespace {\n\n}}";
  70. // Even though the namespaces are empty, but the inner most empty namespace
  71. // block is not affected by the changed ranges.
  72. std::string Expected = "namespace A {\n\n"
  73. "namespace {\n\n}}";
  74. // Set the changed range to be the second "\n".
  75. EXPECT_EQ(Expected, cleanupAroundOffsets({14}, Code));
  76. }
  77. TEST_F(CleanupTest, EmptyNamespaceWithCommentsNoBreakBeforeBrace) {
  78. std::string Code = "namespace A {\n"
  79. "namespace B {\n"
  80. "// Yo\n"
  81. "} // namespace B\n"
  82. "} // namespace A\n"
  83. "namespace C { // Yo\n"
  84. "}";
  85. std::string Expected = "\n\n\n\n\n\n";
  86. std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
  87. std::string Result = cleanup(Code, Ranges);
  88. EXPECT_EQ(Expected, Result);
  89. }
  90. TEST_F(CleanupTest, EmptyNamespaceWithCommentsBreakBeforeBrace) {
  91. std::string Code = "namespace A\n"
  92. "/* Yo */ {\n"
  93. "namespace B\n"
  94. "{\n"
  95. "// Yo\n"
  96. "} // namespace B\n"
  97. "} // namespace A\n"
  98. "namespace C\n"
  99. "{ // Yo\n"
  100. "}\n";
  101. std::string Expected = "\n\n\n\n\n\n\n\n\n\n";
  102. std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
  103. FormatStyle Style = getLLVMStyle();
  104. Style.BraceWrapping.AfterNamespace = true;
  105. std::string Result = cleanup(Code, Ranges, Style);
  106. EXPECT_EQ(Expected, Result);
  107. }
  108. TEST_F(CleanupTest, EmptyNamespaceAroundConditionalCompilation) {
  109. std::string Code = "#ifdef A\n"
  110. "int a;\n"
  111. "int b;\n"
  112. "#else\n"
  113. "#endif\n"
  114. "namespace {}";
  115. std::string Expected = "#ifdef A\n"
  116. "int a;\n"
  117. "int b;\n"
  118. "#else\n"
  119. "#endif\n";
  120. std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
  121. FormatStyle Style = getLLVMStyle();
  122. std::string Result = cleanup(Code, Ranges, Style);
  123. EXPECT_EQ(Expected, Result);
  124. }
  125. TEST_F(CleanupTest, CtorInitializationSimpleRedundantComma) {
  126. std::string Code = "class A {\nA() : , {} };";
  127. std::string Expected = "class A {\nA() {} };";
  128. EXPECT_EQ(Expected, cleanupAroundOffsets({17, 19}, Code));
  129. Code = "class A {\nA() : x(1), {} };";
  130. Expected = "class A {\nA() : x(1) {} };";
  131. EXPECT_EQ(Expected, cleanupAroundOffsets({23}, Code));
  132. Code = "class A {\nA() :,,,,{} };";
  133. Expected = "class A {\nA() {} };";
  134. EXPECT_EQ(Expected, cleanupAroundOffsets({15}, Code));
  135. }
  136. TEST_F(CleanupTest, CtorInitializationSimpleRedundantColon) {
  137. std::string Code = "class A {\nA() : =default; };";
  138. std::string Expected = "class A {\nA() =default; };";
  139. EXPECT_EQ(Expected, cleanupAroundOffsets({15}, Code));
  140. Code = "class A {\nA() : , =default; };";
  141. Expected = "class A {\nA() =default; };";
  142. EXPECT_EQ(Expected, cleanupAroundOffsets({15}, Code));
  143. }
  144. TEST_F(CleanupTest, ListRedundantComma) {
  145. std::string Code = "void f() { std::vector<int> v = {1,2,,,3,{4,5}}; }";
  146. std::string Expected = "void f() { std::vector<int> v = {1,2,3,{4,5}}; }";
  147. EXPECT_EQ(Expected, cleanupAroundOffsets({40}, Code));
  148. Code = "int main() { f(1,,2,3,,4);}";
  149. Expected = "int main() { f(1,2,3,4);}";
  150. EXPECT_EQ(Expected, cleanupAroundOffsets({17, 22}, Code));
  151. }
  152. TEST_F(CleanupTest, NoCleanupsForJavaScript) {
  153. std::string Code = "function f() { var x = [a, b, , c]; }";
  154. std::string Expected = "function f() { var x = [a, b, , c]; }";
  155. const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript);
  156. EXPECT_EQ(Expected, cleanupAroundOffsets({30}, Code, Style));
  157. }
  158. TEST_F(CleanupTest, TrailingCommaInParens) {
  159. std::string Code = "int main() { f(,1,,2,3,f(1,2,),4,,);}";
  160. std::string Expected = "int main() { f(1,2,3,f(1,2),4);}";
  161. EXPECT_EQ(Expected, cleanupAroundOffsets({15, 18, 29, 33}, Code));
  162. // Lambda contents are also checked for trailing commas.
  163. Code = "int main() { [](){f(,1,,2,3,f(1,2,),4,,);}();}";
  164. Expected = "int main() { [](){f(1,2,3,f(1,2),4);}();}";
  165. EXPECT_EQ(Expected, cleanupAroundOffsets({20, 23, 34, 38}, Code));
  166. }
  167. TEST_F(CleanupTest, TrailingCommaInBraces) {
  168. // Trailing comma is allowed in brace list.
  169. // If there was trailing comma in the original code, then trailing comma is
  170. // preserved. In this example, element between the last two commas is deleted
  171. // causing the second-last comma to be redundant.
  172. std::string Code = "void f() { std::vector<int> v = {1,2,3,,}; }";
  173. std::string Expected = "void f() { std::vector<int> v = {1,2,3,}; }";
  174. EXPECT_EQ(Expected, cleanupAroundOffsets({39}, Code));
  175. // If there was no trailing comma in the original code, then trailing comma
  176. // introduced by replacements should be cleaned up. In this example, the
  177. // element after the last comma is deleted causing the last comma to be
  178. // redundant.
  179. Code = "void f() { std::vector<int> v = {1,2,3,}; }";
  180. // FIXME: redundant trailing comma should be removed.
  181. Expected = "void f() { std::vector<int> v = {1,2,3,}; }";
  182. EXPECT_EQ(Expected, cleanupAroundOffsets({39}, Code));
  183. // Still no trailing comma in the original code, but two elements are deleted,
  184. // which makes it seems like there was trailing comma.
  185. Code = "void f() { std::vector<int> v = {1, 2, 3, , }; }";
  186. // FIXME: redundant trailing comma should also be removed.
  187. Expected = "void f() { std::vector<int> v = {1, 2, 3, }; }";
  188. EXPECT_EQ(Expected, cleanupAroundOffsets({42, 44}, Code));
  189. }
  190. TEST_F(CleanupTest, CtorInitializationBracesInParens) {
  191. std::string Code = "class A {\nA() : x({1}),, {} };";
  192. std::string Expected = "class A {\nA() : x({1}) {} };";
  193. EXPECT_EQ(Expected, cleanupAroundOffsets({24, 26}, Code));
  194. }
  195. TEST_F(CleanupTest, RedundantCommaNotInAffectedRanges) {
  196. std::string Code =
  197. "class A {\nA() : x({1}), /* comment */, { int x = 0; } };";
  198. std::string Expected =
  199. "class A {\nA() : x({1}), /* comment */, { int x = 0; } };";
  200. // Set the affected range to be "int x = 0", which does not intercept the
  201. // constructor initialization list.
  202. std::vector<tooling::Range> Ranges(1, tooling::Range(42, 9));
  203. std::string Result = cleanup(Code, Ranges);
  204. EXPECT_EQ(Expected, Result);
  205. Code = "class A {\nA() : x(1), {} };";
  206. Expected = "class A {\nA() : x(1), {} };";
  207. // No range. Fixer should do nothing.
  208. Ranges.clear();
  209. Result = cleanup(Code, Ranges);
  210. EXPECT_EQ(Expected, Result);
  211. }
  212. TEST_F(CleanupTest, RemoveCommentsAroundDeleteCode) {
  213. std::string Code =
  214. "class A {\nA() : x({1}), /* comment */, /* comment */ {} };";
  215. std::string Expected = "class A {\nA() : x({1}) {} };";
  216. EXPECT_EQ(Expected, cleanupAroundOffsets({25, 40}, Code));
  217. Code = "class A {\nA() : x({1}), // comment\n {} };";
  218. Expected = "class A {\nA() : x({1})\n {} };";
  219. EXPECT_EQ(Expected, cleanupAroundOffsets({25}, Code));
  220. Code = "class A {\nA() : x({1}), // comment\n , y(1),{} };";
  221. Expected = "class A {\nA() : x({1}), y(1){} };";
  222. EXPECT_EQ(Expected, cleanupAroundOffsets({38}, Code));
  223. Code = "class A {\nA() : x({1}), \n/* comment */, y(1),{} };";
  224. Expected = "class A {\nA() : x({1}), \n y(1){} };";
  225. EXPECT_EQ(Expected, cleanupAroundOffsets({40}, Code));
  226. Code = "class A {\nA() : , // comment\n y(1),{} };";
  227. Expected = "class A {\nA() : // comment\n y(1){} };";
  228. EXPECT_EQ(Expected, cleanupAroundOffsets({17}, Code));
  229. Code = "class A {\nA() // comment\n : ,,{} };";
  230. Expected = "class A {\nA() // comment\n {} };";
  231. EXPECT_EQ(Expected, cleanupAroundOffsets({30}, Code));
  232. Code = "class A {\nA() // comment\n : ,,=default; };";
  233. Expected = "class A {\nA() // comment\n =default; };";
  234. EXPECT_EQ(Expected, cleanupAroundOffsets({30}, Code));
  235. }
  236. TEST_F(CleanupTest, CtorInitializerInNamespace) {
  237. std::string Code = "namespace A {\n"
  238. "namespace B {\n" // missing r_brace
  239. "} // namespace A\n\n"
  240. "namespace C {\n"
  241. "class A { A() : x(0),, {} };\n"
  242. "inline namespace E { namespace { } }\n"
  243. "}";
  244. std::string Expected = "namespace A {\n"
  245. "\n\n\nnamespace C {\n"
  246. "class A { A() : x(0) {} };\n \n"
  247. "}";
  248. std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
  249. std::string Result = cleanup(Code, Ranges);
  250. EXPECT_EQ(Expected, Result);
  251. }
  252. class CleanUpReplacementsTest : public ReplacementTest {
  253. protected:
  254. tooling::Replacement createReplacement(unsigned Offset, unsigned Length,
  255. StringRef Text) {
  256. return tooling::Replacement(FileName, Offset, Length, Text);
  257. }
  258. tooling::Replacement createInsertion(StringRef IncludeDirective) {
  259. return createReplacement(UINT_MAX, 0, IncludeDirective);
  260. }
  261. tooling::Replacement createDeletion(StringRef HeaderName) {
  262. return createReplacement(UINT_MAX, 1, HeaderName);
  263. }
  264. inline std::string apply(StringRef Code,
  265. const tooling::Replacements &Replaces) {
  266. auto CleanReplaces = cleanupAroundReplacements(Code, Replaces, Style);
  267. EXPECT_TRUE(static_cast<bool>(CleanReplaces))
  268. << llvm::toString(CleanReplaces.takeError()) << "\n";
  269. auto Result = applyAllReplacements(Code, *CleanReplaces);
  270. EXPECT_TRUE(static_cast<bool>(Result));
  271. return *Result;
  272. }
  273. inline std::string formatAndApply(StringRef Code,
  274. const tooling::Replacements &Replaces) {
  275. auto CleanReplaces = cleanupAroundReplacements(Code, Replaces, Style);
  276. EXPECT_TRUE(static_cast<bool>(CleanReplaces))
  277. << llvm::toString(CleanReplaces.takeError()) << "\n";
  278. auto FormattedReplaces = formatReplacements(Code, *CleanReplaces, Style);
  279. EXPECT_TRUE(static_cast<bool>(FormattedReplaces))
  280. << llvm::toString(FormattedReplaces.takeError()) << "\n";
  281. auto Result = applyAllReplacements(Code, *FormattedReplaces);
  282. EXPECT_TRUE(static_cast<bool>(Result));
  283. return *Result;
  284. }
  285. int getOffset(StringRef Code, int Line, int Column) {
  286. RewriterTestContext Context;
  287. FileID ID = Context.createInMemoryFile(FileName, Code);
  288. auto DecomposedLocation =
  289. Context.Sources.getDecomposedLoc(Context.getLocation(ID, Line, Column));
  290. return DecomposedLocation.second;
  291. }
  292. const std::string FileName = "fix.cpp";
  293. FormatStyle Style = getLLVMStyle();
  294. };
  295. TEST_F(CleanUpReplacementsTest, FixOnlyAffectedCodeAfterReplacements) {
  296. std::string Code = "namespace A {\n"
  297. "namespace B {\n"
  298. " int x;\n"
  299. "} // namespace B\n"
  300. "} // namespace A\n"
  301. "\n"
  302. "namespace C {\n"
  303. "namespace D { int i; }\n"
  304. "inline namespace E { namespace { int y; } }\n"
  305. "int x= 0;"
  306. "}";
  307. std::string Expected = "\n\nnamespace C {\n"
  308. "namespace D { int i; }\n\n"
  309. "int x= 0;"
  310. "}";
  311. tooling::Replacements Replaces =
  312. toReplacements({createReplacement(getOffset(Code, 3, 3), 6, ""),
  313. createReplacement(getOffset(Code, 9, 34), 6, "")});
  314. EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
  315. }
  316. TEST_F(CleanUpReplacementsTest, InsertMultipleIncludesLLVMStyle) {
  317. std::string Code = "#include \"x/fix.h\"\n"
  318. "#include \"a.h\"\n"
  319. "#include \"b.h\"\n"
  320. "#include \"z.h\"\n"
  321. "#include \"clang/Format/Format.h\"\n"
  322. "#include <memory>\n";
  323. std::string Expected = "#include \"x/fix.h\"\n"
  324. "#include \"a.h\"\n"
  325. "#include \"b.h\"\n"
  326. "#include \"new/new.h\"\n"
  327. "#include \"z.h\"\n"
  328. "#include \"clang/Format/Format.h\"\n"
  329. "#include <list>\n"
  330. "#include <memory>\n";
  331. tooling::Replacements Replaces =
  332. toReplacements({createInsertion("#include <list>"),
  333. createInsertion("#include \"new/new.h\"")});
  334. EXPECT_EQ(Expected, apply(Code, Replaces));
  335. }
  336. TEST_F(CleanUpReplacementsTest, InsertMultipleIncludesGoogleStyle) {
  337. std::string Code = "#include \"x/fix.h\"\n"
  338. "\n"
  339. "#include <vector>\n"
  340. "\n"
  341. "#include \"y/a.h\"\n"
  342. "#include \"z/b.h\"\n";
  343. std::string Expected = "#include \"x/fix.h\"\n"
  344. "\n"
  345. "#include <list>\n"
  346. "#include <vector>\n"
  347. "\n"
  348. "#include \"x/x.h\"\n"
  349. "#include \"y/a.h\"\n"
  350. "#include \"z/b.h\"\n";
  351. tooling::Replacements Replaces =
  352. toReplacements({createInsertion("#include <list>"),
  353. createInsertion("#include \"x/x.h\"")});
  354. Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
  355. EXPECT_EQ(Expected, apply(Code, Replaces));
  356. }
  357. TEST_F(CleanUpReplacementsTest, InsertMultipleNewHeadersAndSortLLVM) {
  358. std::string Code = "\nint x;";
  359. std::string Expected = "\n#include \"fix.h\"\n"
  360. "#include \"a.h\"\n"
  361. "#include \"b.h\"\n"
  362. "#include \"c.h\"\n"
  363. "#include <list>\n"
  364. "#include <vector>\n"
  365. "int x;";
  366. tooling::Replacements Replaces = toReplacements(
  367. {createInsertion("#include \"a.h\""), createInsertion("#include \"c.h\""),
  368. createInsertion("#include \"b.h\""),
  369. createInsertion("#include <vector>"), createInsertion("#include <list>"),
  370. createInsertion("#include \"fix.h\"")});
  371. EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
  372. }
  373. TEST_F(CleanUpReplacementsTest, InsertMultipleNewHeadersAndSortGoogle) {
  374. std::string Code = "\nint x;";
  375. std::string Expected = "\n#include \"fix.h\"\n"
  376. "\n"
  377. "#include <list>\n"
  378. "#include <vector>\n"
  379. "\n"
  380. "#include \"a.h\"\n"
  381. "#include \"b.h\"\n"
  382. "#include \"c.h\"\n"
  383. "int x;";
  384. tooling::Replacements Replaces = toReplacements(
  385. {createInsertion("#include \"a.h\""), createInsertion("#include \"c.h\""),
  386. createInsertion("#include \"b.h\""),
  387. createInsertion("#include <vector>"), createInsertion("#include <list>"),
  388. createInsertion("#include \"fix.h\"")});
  389. Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
  390. EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
  391. }
  392. TEST_F(CleanUpReplacementsTest, NoNewLineAtTheEndOfCodeMultipleInsertions) {
  393. std::string Code = "#include <map>";
  394. // FIXME: a better behavior is to only append on newline to Code, but this
  395. // case should be rare in practice.
  396. std::string Expected =
  397. "#include <map>\n#include <string>\n\n#include <vector>\n";
  398. tooling::Replacements Replaces =
  399. toReplacements({createInsertion("#include <string>"),
  400. createInsertion("#include <vector>")});
  401. EXPECT_EQ(Expected, apply(Code, Replaces));
  402. }
  403. TEST_F(CleanUpReplacementsTest, FormatCorrectLineWhenHeadersAreInserted) {
  404. std::string Code = "\n"
  405. "int x;\n"
  406. "int a;\n"
  407. "int a;\n"
  408. "int a;";
  409. std::string Expected = "\n#include \"x.h\"\n"
  410. "#include \"y.h\"\n"
  411. "#include \"clang/x/x.h\"\n"
  412. "#include <list>\n"
  413. "#include <vector>\n"
  414. "int x;\n"
  415. "int a;\n"
  416. "int b;\n"
  417. "int a;";
  418. tooling::Replacements Replaces = toReplacements(
  419. {createReplacement(getOffset(Code, 4, 8), 1, "b"),
  420. createInsertion("#include <vector>"), createInsertion("#include <list>"),
  421. createInsertion("#include \"clang/x/x.h\""),
  422. createInsertion("#include \"y.h\""),
  423. createInsertion("#include \"x.h\"")});
  424. EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
  425. }
  426. TEST_F(CleanUpReplacementsTest, SimpleDeleteIncludes) {
  427. std::string Code = "#include \"abc.h\"\n"
  428. "#include \"xyz.h\" // comment\n"
  429. "#include \"xyz\"\n"
  430. "int x;\n";
  431. std::string Expected = "#include \"xyz\"\n"
  432. "int x;\n";
  433. tooling::Replacements Replaces =
  434. toReplacements({createDeletion("abc.h"), createDeletion("xyz.h")});
  435. EXPECT_EQ(Expected, apply(Code, Replaces));
  436. }
  437. TEST_F(CleanUpReplacementsTest, InsertionAndDeleteHeader) {
  438. std::string Code = "#include \"a.h\"\n"
  439. "\n"
  440. "#include <vector>\n";
  441. std::string Expected = "#include \"a.h\"\n"
  442. "\n"
  443. "#include <map>\n";
  444. tooling::Replacements Replaces = toReplacements(
  445. {createDeletion("<vector>"), createInsertion("#include <map>")});
  446. EXPECT_EQ(Expected, apply(Code, Replaces));
  447. }
  448. } // end namespace
  449. } // end namespace format
  450. } // end namespace clang