CleanupTest.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. //===- unittest/Format/CleanupTest.cpp - Code cleanup unit tests ----------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include "clang/Format/Format.h"
  10. #include "../Tooling/RewriterTestContext.h"
  11. #include "clang/Tooling/Core/Replacement.h"
  12. #include "gtest/gtest.h"
  13. namespace clang {
  14. namespace format {
  15. namespace {
  16. class CleanupTest : public ::testing::Test {
  17. protected:
  18. std::string cleanup(llvm::StringRef Code,
  19. const std::vector<tooling::Range> &Ranges,
  20. const FormatStyle &Style = getLLVMStyle()) {
  21. tooling::Replacements Replaces = format::cleanup(Style, Code, Ranges);
  22. std::string Result = applyAllReplacements(Code, Replaces);
  23. EXPECT_NE("", Result);
  24. return Result;
  25. }
  26. };
  27. TEST_F(CleanupTest, DeleteEmptyNamespaces) {
  28. std::string Code = "namespace A {\n"
  29. "namespace B {\n"
  30. "} // namespace B\n"
  31. "} // namespace A\n\n"
  32. "namespace C {\n"
  33. "namespace D { int i; }\n"
  34. "inline namespace E { namespace { } }\n"
  35. "}";
  36. std::string Expected = "\n\n\n\n\nnamespace C {\n"
  37. "namespace D { int i; }\n \n"
  38. "}";
  39. std::vector<tooling::Range> Ranges;
  40. Ranges.push_back(tooling::Range(28, 0));
  41. Ranges.push_back(tooling::Range(91, 6));
  42. Ranges.push_back(tooling::Range(132, 0));
  43. std::string Result = cleanup(Code, Ranges);
  44. EXPECT_EQ(Expected, Result);
  45. }
  46. TEST_F(CleanupTest, NamespaceWithSyntaxError) {
  47. std::string Code = "namespace A {\n"
  48. "namespace B {\n" // missing r_brace
  49. "} // namespace A\n\n"
  50. "namespace C {\n"
  51. "namespace D int i; }\n"
  52. "inline namespace E { namespace { } }\n"
  53. "}";
  54. std::string Expected = "namespace A {\n"
  55. "\n\n\nnamespace C {\n"
  56. "namespace D int i; }\n \n"
  57. "}";
  58. std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
  59. std::string Result = cleanup(Code, Ranges);
  60. EXPECT_EQ(Expected, Result);
  61. }
  62. TEST_F(CleanupTest, EmptyNamespaceNotAffected) {
  63. std::string Code = "namespace A {\n\n"
  64. "namespace {\n\n}}";
  65. // Even though the namespaces are empty, but the inner most empty namespace
  66. // block is not affected by the changed ranges.
  67. std::string Expected = "namespace A {\n\n"
  68. "namespace {\n\n}}";
  69. // Set the changed range to be the second "\n".
  70. std::vector<tooling::Range> Ranges(1, tooling::Range(14, 0));
  71. std::string Result = cleanup(Code, Ranges);
  72. EXPECT_EQ(Expected, Result);
  73. }
  74. TEST_F(CleanupTest, EmptyNamespaceWithCommentsNoBreakBeforeBrace) {
  75. std::string Code = "namespace A {\n"
  76. "namespace B {\n"
  77. "// Yo\n"
  78. "} // namespace B\n"
  79. "} // namespace A\n"
  80. "namespace C { // Yo\n"
  81. "}";
  82. std::string Expected = "\n\n\n\n\n\n";
  83. std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
  84. std::string Result = cleanup(Code, Ranges);
  85. EXPECT_EQ(Expected, Result);
  86. }
  87. TEST_F(CleanupTest, EmptyNamespaceWithCommentsBreakBeforeBrace) {
  88. std::string Code = "namespace A\n"
  89. "/* Yo */ {\n"
  90. "namespace B\n"
  91. "{\n"
  92. "// Yo\n"
  93. "} // namespace B\n"
  94. "} // namespace A\n"
  95. "namespace C\n"
  96. "{ // Yo\n"
  97. "}\n";
  98. std::string Expected = "\n\n\n\n\n\n\n\n\n\n";
  99. std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
  100. FormatStyle Style = getLLVMStyle();
  101. Style.BraceWrapping.AfterNamespace = true;
  102. std::string Result = cleanup(Code, Ranges, Style);
  103. EXPECT_EQ(Expected, Result);
  104. }
  105. TEST_F(CleanupTest, CtorInitializationSimpleRedundantComma) {
  106. std::string Code = "class A {\nA() : , {} };";
  107. std::string Expected = "class A {\nA() {} };";
  108. std::vector<tooling::Range> Ranges;
  109. Ranges.push_back(tooling::Range(17, 0));
  110. Ranges.push_back(tooling::Range(19, 0));
  111. std::string Result = cleanup(Code, Ranges);
  112. EXPECT_EQ(Expected, Result);
  113. Code = "class A {\nA() : x(1), {} };";
  114. Expected = "class A {\nA() : x(1) {} };";
  115. Ranges.clear();
  116. Ranges.push_back(tooling::Range(23, 0));
  117. Result = cleanup(Code, Ranges);
  118. EXPECT_EQ(Expected, Result);
  119. Code = "class A {\nA() :,,,,{} };";
  120. Expected = "class A {\nA() {} };";
  121. Ranges.clear();
  122. Ranges.push_back(tooling::Range(15, 0));
  123. Result = cleanup(Code, Ranges);
  124. EXPECT_EQ(Expected, Result);
  125. }
  126. TEST_F(CleanupTest, ListSimpleRedundantComma) {
  127. std::string Code = "void f() { std::vector<int> v = {1,2,,,3,{4,5}}; }";
  128. std::string Expected = "void f() { std::vector<int> v = {1,2,3,{4,5}}; }";
  129. std::vector<tooling::Range> Ranges;
  130. Ranges.push_back(tooling::Range(40, 0));
  131. std::string Result = cleanup(Code, Ranges);
  132. EXPECT_EQ(Expected, Result);
  133. Code = "int main() { f(1,,2,3,,4);}";
  134. Expected = "int main() { f(1,2,3,4);}";
  135. Ranges.clear();
  136. Ranges.push_back(tooling::Range(17, 0));
  137. Ranges.push_back(tooling::Range(22, 0));
  138. Result = cleanup(Code, Ranges);
  139. EXPECT_EQ(Expected, Result);
  140. }
  141. TEST_F(CleanupTest, CtorInitializationBracesInParens) {
  142. std::string Code = "class A {\nA() : x({1}),, {} };";
  143. std::string Expected = "class A {\nA() : x({1}) {} };";
  144. std::vector<tooling::Range> Ranges;
  145. Ranges.push_back(tooling::Range(24, 0));
  146. Ranges.push_back(tooling::Range(26, 0));
  147. std::string Result = cleanup(Code, Ranges);
  148. EXPECT_EQ(Expected, Result);
  149. }
  150. TEST_F(CleanupTest, RedundantCommaNotInAffectedRanges) {
  151. std::string Code =
  152. "class A {\nA() : x({1}), /* comment */, { int x = 0; } };";
  153. std::string Expected =
  154. "class A {\nA() : x({1}), /* comment */, { int x = 0; } };";
  155. // Set the affected range to be "int x = 0", which does not intercept the
  156. // constructor initialization list.
  157. std::vector<tooling::Range> Ranges(1, tooling::Range(42, 9));
  158. std::string Result = cleanup(Code, Ranges);
  159. EXPECT_EQ(Expected, Result);
  160. Code = "class A {\nA() : x(1), {} };";
  161. Expected = "class A {\nA() : x(1), {} };";
  162. // No range. Fixer should do nothing.
  163. Ranges.clear();
  164. Result = cleanup(Code, Ranges);
  165. EXPECT_EQ(Expected, Result);
  166. }
  167. // FIXME: delete comments too.
  168. TEST_F(CleanupTest, CtorInitializationCommentAroundCommas) {
  169. // Remove redundant commas around comment.
  170. std::string Code = "class A {\nA() : x({1}), /* comment */, {} };";
  171. std::string Expected = "class A {\nA() : x({1}) /* comment */ {} };";
  172. std::vector<tooling::Range> Ranges;
  173. Ranges.push_back(tooling::Range(25, 0));
  174. Ranges.push_back(tooling::Range(40, 0));
  175. std::string Result = cleanup(Code, Ranges);
  176. EXPECT_EQ(Expected, Result);
  177. // Remove trailing comma and ignore comment.
  178. Code = "class A {\nA() : x({1}), // comment\n{} };";
  179. Expected = "class A {\nA() : x({1}) // comment\n{} };";
  180. Ranges = std::vector<tooling::Range>(1, tooling::Range(25, 0));
  181. Result = cleanup(Code, Ranges);
  182. EXPECT_EQ(Expected, Result);
  183. // Remove trailing comma and ignore comment.
  184. Code = "class A {\nA() : x({1}), // comment\n , y(1),{} };";
  185. Expected = "class A {\nA() : x({1}), // comment\n y(1){} };";
  186. Ranges = std::vector<tooling::Range>(1, tooling::Range(38, 0));
  187. Result = cleanup(Code, Ranges);
  188. EXPECT_EQ(Expected, Result);
  189. // Remove trailing comma and ignore comment.
  190. Code = "class A {\nA() : x({1}), \n/* comment */, y(1),{} };";
  191. Expected = "class A {\nA() : x({1}), \n/* comment */ y(1){} };";
  192. Ranges = std::vector<tooling::Range>(1, tooling::Range(40, 0));
  193. Result = cleanup(Code, Ranges);
  194. EXPECT_EQ(Expected, Result);
  195. // Remove trailing comma and ignore comment.
  196. Code = "class A {\nA() : , // comment\n y(1),{} };";
  197. Expected = "class A {\nA() : // comment\n y(1){} };";
  198. Ranges = std::vector<tooling::Range>(1, tooling::Range(17, 0));
  199. Result = cleanup(Code, Ranges);
  200. EXPECT_EQ(Expected, Result);
  201. }
  202. TEST_F(CleanupTest, CtorInitializerInNamespace) {
  203. std::string Code = "namespace A {\n"
  204. "namespace B {\n" // missing r_brace
  205. "} // namespace A\n\n"
  206. "namespace C {\n"
  207. "class A { A() : x(0),, {} };\n"
  208. "inline namespace E { namespace { } }\n"
  209. "}";
  210. std::string Expected = "namespace A {\n"
  211. "\n\n\nnamespace C {\n"
  212. "class A { A() : x(0) {} };\n \n"
  213. "}";
  214. std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
  215. std::string Result = cleanup(Code, Ranges);
  216. EXPECT_EQ(Expected, Result);
  217. }
  218. class CleanUpReplacementsTest : public ::testing::Test {
  219. protected:
  220. tooling::Replacement createReplacement(SourceLocation Start, unsigned Length,
  221. llvm::StringRef ReplacementText) {
  222. return tooling::Replacement(Context.Sources, Start, Length,
  223. ReplacementText);
  224. }
  225. RewriterTestContext Context;
  226. };
  227. TEST_F(CleanUpReplacementsTest, FixOnlyAffectedCodeAfterReplacements) {
  228. std::string Code = "namespace A {\n"
  229. "namespace B {\n"
  230. " int x;\n"
  231. "} // namespace B\n"
  232. "} // namespace A\n"
  233. "\n"
  234. "namespace C {\n"
  235. "namespace D { int i; }\n"
  236. "inline namespace E { namespace { int y; } }\n"
  237. "int x= 0;"
  238. "}";
  239. std::string Expected = "\n\nnamespace C {\n"
  240. "namespace D { int i; }\n\n"
  241. "int x= 0;"
  242. "}";
  243. FileID ID = Context.createInMemoryFile("fix.cpp", Code);
  244. tooling::Replacements Replaces;
  245. Replaces.insert(tooling::Replacement(Context.Sources,
  246. Context.getLocation(ID, 3, 3), 6, ""));
  247. Replaces.insert(tooling::Replacement(Context.Sources,
  248. Context.getLocation(ID, 9, 34), 6, ""));
  249. format::FormatStyle Style = format::getLLVMStyle();
  250. auto FinalReplaces = formatReplacements(
  251. Code, cleanupAroundReplacements(Code, Replaces, Style), Style);
  252. EXPECT_EQ(Expected, applyAllReplacements(Code, FinalReplaces));
  253. }
  254. } // end namespace
  255. } // end namespace format
  256. } // end namespace clang