rewriter_test.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "migrate_cpp/rewriter.h"
  5. #include <gmock/gmock.h>
  6. #include <gtest/gtest.h>
  7. #include "clang/AST/ASTConsumer.h"
  8. #include "clang/Frontend/CompilerInstance.h"
  9. #include "clang/Frontend/FrontendAction.h"
  10. #include "clang/Tooling/Tooling.h"
  11. namespace Carbon::Testing {
  12. namespace {
  13. // Represents C++ source code with at most one region enclosed in $[[...]]$ as
  14. // an annotated range.
  15. class Annotations {
  16. public:
  17. explicit Annotations(llvm::StringRef annotated_source) {
  18. size_t index = annotated_source.find("$[[");
  19. if (index == llvm::StringRef::npos) {
  20. source_code_ = std::string(annotated_source);
  21. return;
  22. }
  23. start_ = index;
  24. end_ = annotated_source.find("]]$", index);
  25. CARBON_CHECK(end_ != llvm::StringRef::npos)
  26. << "Found `$[[` but no matching `]]$`";
  27. source_code_ = (llvm::Twine(annotated_source.substr(0, start_)) +
  28. annotated_source.substr(start_ + 3, end_ - start_ - 3) +
  29. annotated_source.substr(end_ + 3))
  30. .str();
  31. // Update `end_` so that it is relative to the unannotated source (which
  32. // means three characters earlier due to the `$[[` being removed.
  33. end_ -= 3;
  34. }
  35. // Returns a view into the unannotated source.
  36. auto source() const -> llvm::StringRef { return source_code_; }
  37. // Returns the offsets in the file representing the annotated range if they
  38. // exist and `{0, std::numeric_limits<size_t>::max()}` otherwise.
  39. auto range() const -> std::pair<size_t, size_t> {
  40. return std::pair(start_, end_);
  41. }
  42. private:
  43. std::string source_code_;
  44. size_t start_ = 0;
  45. size_t end_ = std::numeric_limits<size_t>::max();
  46. };
  47. // Rewrites the `cpp_code`, return the Carbon equivalent. If the text has no
  48. // source range annotated with $[[...]]$, the entire translation unit will be
  49. // migrated and output. Otherwise, only the migrated output corresponding to the
  50. // annotated range will be output. No more than one range may be annotated at
  51. // all.
  52. //
  53. // This annotation mechanism is useful in that it allows us to specifically test
  54. // the migration associated with specific nodes even when they require some
  55. // additional context that we do not wish to be covered by the test.
  56. auto RewriteText(llvm::StringRef cpp_code) -> std::string {
  57. std::string result;
  58. Annotations annotated_cpp_code(cpp_code);
  59. bool success = clang::tooling::runToolOnCodeWithArgs(
  60. std::make_unique<MigrationAction>(result, annotated_cpp_code.range()),
  61. annotated_cpp_code.source(), {}, "test.cc", "clang-tool",
  62. std::make_shared<clang::PCHContainerOperations>(),
  63. clang::tooling::FileContentMappings());
  64. return success ? result : "";
  65. }
  66. TEST(Rewriter, BoolLiteral) {
  67. EXPECT_EQ(RewriteText("bool x = $[[true]]$;"), "true");
  68. EXPECT_EQ(RewriteText("bool x = $[[false]]$;"), "false");
  69. }
  70. TEST(Rewriter, IntegerLiteral) {
  71. EXPECT_EQ(RewriteText("int x = $[[0]]$;"), "0");
  72. EXPECT_EQ(RewriteText("int x = $[[1]]$;"), "1");
  73. EXPECT_EQ(RewriteText("int x = $[[1234]]$;"), "1234");
  74. EXPECT_EQ(RewriteText("int x = $[[12'34]]$;"), "12_34");
  75. EXPECT_EQ(RewriteText("int x = $[[12'3'4]]$;"), "12_3_4");
  76. }
  77. TEST(Rewriter, SingleDeclaration) {
  78. EXPECT_EQ(RewriteText("bool b;"), "var b: bool;\n");
  79. EXPECT_EQ(RewriteText("int i;"), "var i: i32;\n");
  80. EXPECT_EQ(RewriteText("const bool b = false;"), "let b: bool = false;\n");
  81. EXPECT_EQ(RewriteText("const int i = 17;"), "let i: i32 = 17;\n");
  82. EXPECT_EQ(RewriteText("bool const b = false;"), "let b: bool = false;\n");
  83. EXPECT_EQ(RewriteText("int const i = 1234;"), "let i: i32 = 1234;\n");
  84. }
  85. TEST(Rewriter, Pointers) {
  86. // TODO: Add tests for pointers-to-const when the syntax is nailed down.
  87. EXPECT_EQ(RewriteText("bool b;\n"
  88. "$[[bool *p = &b]]$;"),
  89. "var p: bool* = &b");
  90. EXPECT_EQ(RewriteText("bool b;\n"
  91. "$[[bool * const p = &b]]$;"),
  92. "let p: bool* = &b");
  93. // Pointers and non-pointers on the same DeclStmt.
  94. EXPECT_EQ(RewriteText("bool b, *p;\n"),
  95. "var b: bool;\n"
  96. "var p: bool*;\n");
  97. EXPECT_EQ(RewriteText("bool b, *p = &b;\n"),
  98. "var b: bool;\n"
  99. "var p: bool* = &b;\n");
  100. }
  101. TEST(Rewriter, DeclarationComma) {
  102. EXPECT_EQ(RewriteText("int x, y;"),
  103. "var x: i32;\n"
  104. "var y: i32;\n");
  105. EXPECT_EQ(RewriteText("int x = 7, y;"),
  106. "var x: i32 = 7;\n"
  107. "var y: i32;\n");
  108. EXPECT_EQ(RewriteText("const int x = 1, y = 2;"),
  109. "let x: i32 = 1;\n"
  110. "let y: i32 = 2;\n");
  111. EXPECT_EQ(RewriteText("int const x = 1234, y = 5678;"),
  112. "let x: i32 = 1234;\n"
  113. "let y: i32 = 5678;\n");
  114. }
  115. TEST(Rewriter, FunctionDeclaration) {
  116. // Function declarations and definitions returning void.
  117. EXPECT_EQ(RewriteText("void f();"), "fn f() -> ();\n");
  118. EXPECT_EQ(RewriteText("void f() {}"),
  119. "fn f() -> () {\n"
  120. "}\n");
  121. // Function declarations and definitions returning int.
  122. EXPECT_EQ(RewriteText("int f();"), "fn f() -> i32;\n");
  123. EXPECT_EQ(RewriteText("int f() { return 0; }"),
  124. "fn f() -> i32 {\n"
  125. "return 0;\n"
  126. "}\n");
  127. // Function declarations and definitions with a single parameter.
  128. EXPECT_EQ(RewriteText("int f(bool);"), "fn f(_: bool) -> i32;\n");
  129. EXPECT_EQ(RewriteText("int f(bool b);"), "fn f(b: bool) -> i32;\n");
  130. EXPECT_EQ(RewriteText("int f(bool) { return 0; }"),
  131. "fn f(_: bool) -> i32 {\n"
  132. "return 0;\n"
  133. "}\n");
  134. EXPECT_EQ(RewriteText("int f(bool b) { return 0; }"),
  135. "fn f(b: bool) -> i32 {\n"
  136. "return 0;\n"
  137. "}\n");
  138. // Function declarations and definitions with a multiple parameters.
  139. EXPECT_EQ(RewriteText("int f(bool, int);"),
  140. "fn f(_: bool, _: i32) -> i32;\n");
  141. EXPECT_EQ(RewriteText("int f(bool b, int n);"),
  142. "fn f(b: bool, n: i32) -> i32;\n");
  143. EXPECT_EQ(RewriteText("int f(bool, int n) { return 0; }"),
  144. "fn f(_: bool, n: i32) -> i32 {\n"
  145. "return 0;\n"
  146. "}\n");
  147. EXPECT_EQ(RewriteText("int f(bool b, int n) { return 0; }"),
  148. "fn f(b: bool, n: i32) -> i32 {\n"
  149. "return 0;\n"
  150. "}\n");
  151. EXPECT_EQ(RewriteText("int f(bool b, int n = 3) { return n; }"),
  152. "fn f(b: bool, n: i32 = 3) -> i32 {\n"
  153. "return n;\n"
  154. "}\n");
  155. // Function declarations with trailing-return syntax.
  156. EXPECT_EQ(RewriteText("auto f(bool b, int n = 3) -> int;"),
  157. "fn f(b: bool, n: i32 = 3) -> i32;\n");
  158. EXPECT_EQ(RewriteText("auto f(bool b, int n = 3) -> int { return n; }"),
  159. "fn f(b: bool, n: i32 = 3) -> i32 {\n"
  160. "return n;\n"
  161. "}\n");
  162. }
  163. } // namespace
  164. } // namespace Carbon::Testing