CodeExpanderTest.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. //===- llvm/unittest/TableGen/CodeExpanderTest.cpp - 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 "GlobalISel/CodeExpander.h"
  9. #include "GlobalISel/CodeExpansions.h"
  10. #include "llvm/Support/raw_ostream.h"
  11. #include "llvm/TableGen/Error.h"
  12. #include "gtest/gtest.h"
  13. using namespace llvm;
  14. static StringRef bufferize(StringRef Str) {
  15. std::unique_ptr<MemoryBuffer> Buffer =
  16. MemoryBuffer::getMemBufferCopy(Str, "TestBuffer");
  17. StringRef StrBufferRef = Buffer->getBuffer();
  18. SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc());
  19. return StrBufferRef;
  20. }
  21. class RAIIDiagnosticChecker {
  22. std::string EmittedDiags;
  23. raw_string_ostream OS;
  24. std::vector<SMDiagnostic> Expected;
  25. std::vector<SMDiagnostic> Received;
  26. public:
  27. RAIIDiagnosticChecker() : OS(EmittedDiags) {
  28. SrcMgr.setDiagHandler(handler, this);
  29. }
  30. ~RAIIDiagnosticChecker() {
  31. SrcMgr.setDiagHandler(nullptr);
  32. EXPECT_EQ(Received.size(), Expected.size());
  33. for (unsigned i = 0; i < Received.size() && i < Expected.size(); ++i) {
  34. EXPECT_EQ(Received[i].getLoc(), Expected[i].getLoc());
  35. EXPECT_EQ(Received[i].getFilename(), Expected[i].getFilename());
  36. EXPECT_EQ(Received[i].getKind(), Expected[i].getKind());
  37. EXPECT_EQ(Received[i].getLineNo(), Expected[i].getLineNo());
  38. EXPECT_EQ(Received[i].getColumnNo(), Expected[i].getColumnNo());
  39. EXPECT_EQ(Received[i].getMessage(), Expected[i].getMessage());
  40. EXPECT_EQ(Received[i].getLineContents(), Expected[i].getLineContents());
  41. EXPECT_EQ(Received[i].getRanges(), Expected[i].getRanges());
  42. }
  43. if (testing::Test::HasFailure())
  44. errs() << "Emitted diagnostic:\n" << OS.str();
  45. }
  46. void expect(SMDiagnostic D) { Expected.push_back(D); }
  47. void diag(const SMDiagnostic &D) {
  48. Received.push_back(D);
  49. }
  50. static void handler(const SMDiagnostic &D, void *Context) {
  51. RAIIDiagnosticChecker *Self = static_cast<RAIIDiagnosticChecker *>(Context);
  52. Self->diag(D);
  53. SrcMgr.setDiagHandler(nullptr);
  54. SrcMgr.PrintMessage(Self->OS, D);
  55. SrcMgr.setDiagHandler(handler, Context);
  56. };
  57. };
  58. TEST(CodeExpander, NoExpansions) {
  59. std::string Result;
  60. raw_string_ostream OS(Result);
  61. CodeExpansions Expansions;
  62. RAIIDiagnosticChecker DiagChecker;
  63. CodeExpander("No expansions", Expansions, SMLoc(), false).emit(OS);
  64. EXPECT_EQ(OS.str(), "No expansions");
  65. }
  66. // Indentation is applied to all lines except the first
  67. TEST(CodeExpander, Indentation) {
  68. std::string Result;
  69. raw_string_ostream OS(Result);
  70. CodeExpansions Expansions;
  71. RAIIDiagnosticChecker DiagChecker;
  72. CodeExpander("No expansions\nsecond line\nthird line", Expansions, SMLoc(),
  73. false, " ")
  74. .emit(OS);
  75. EXPECT_EQ(OS.str(), "No expansions\n second line\n third line");
  76. }
  77. // \ is an escape character that removes special meanings from the next
  78. // character.
  79. TEST(CodeExpander, Escape) {
  80. std::string Result;
  81. raw_string_ostream OS(Result);
  82. CodeExpansions Expansions;
  83. RAIIDiagnosticChecker DiagChecker;
  84. CodeExpander("\\\\\\a\\$", Expansions, SMLoc(), false).emit(OS);
  85. EXPECT_EQ(OS.str(), "\\a$");
  86. }
  87. // $foo is not an expansion. It should warn though.
  88. TEST(CodeExpander, NotAnExpansion) {
  89. std::string Result;
  90. raw_string_ostream OS(Result);
  91. CodeExpansions Expansions;
  92. RAIIDiagnosticChecker DiagChecker;
  93. StringRef In = bufferize(" $foo");
  94. CodeExpander(" $foo", Expansions, SMLoc::getFromPointer(In.data()), false)
  95. .emit(OS);
  96. EXPECT_EQ(OS.str(), " $foo");
  97. DiagChecker.expect(SMDiagnostic(
  98. SrcMgr, SMLoc::getFromPointer(In.data() + 1), "TestBuffer", 1, 1,
  99. SourceMgr::DK_Warning, "Assuming missing escape character", " $foo", {}));
  100. }
  101. // \$foo is not an expansion but shouldn't warn as it's using the escape.
  102. TEST(CodeExpander, EscapedNotAnExpansion) {
  103. std::string Result;
  104. raw_string_ostream OS(Result);
  105. CodeExpansions Expansions;
  106. RAIIDiagnosticChecker DiagChecker;
  107. CodeExpander("\\$foo", Expansions, SMLoc(), false).emit(OS);
  108. EXPECT_EQ(OS.str(), "$foo");
  109. }
  110. // \${foo is not an expansion but shouldn't warn as it's using the escape.
  111. TEST(CodeExpander, EscapedUnterminatedExpansion) {
  112. std::string Result;
  113. raw_string_ostream OS(Result);
  114. CodeExpansions Expansions;
  115. RAIIDiagnosticChecker DiagChecker;
  116. CodeExpander("\\${foo", Expansions, SMLoc(), false).emit(OS);
  117. EXPECT_EQ(OS.str(), "${foo");
  118. }
  119. // \${foo is not an expansion but shouldn't warn as it's using the escape.
  120. TEST(CodeExpander, EscapedExpansion) {
  121. std::string Result;
  122. raw_string_ostream OS(Result);
  123. CodeExpansions Expansions;
  124. RAIIDiagnosticChecker DiagChecker;
  125. CodeExpander("\\${foo}", Expansions, SMLoc(), false).emit(OS);
  126. EXPECT_EQ(OS.str(), "${foo}");
  127. }
  128. // ${foo} is an undefined expansion and should error.
  129. TEST(CodeExpander, UndefinedExpansion) {
  130. std::string Result;
  131. raw_string_ostream OS(Result);
  132. CodeExpansions Expansions;
  133. Expansions.declare("bar", "expansion");
  134. RAIIDiagnosticChecker DiagChecker;
  135. CodeExpander("${foo}${bar}", Expansions, SMLoc(), false).emit(OS);
  136. EXPECT_EQ(OS.str(), "expansion");
  137. DiagChecker.expect(
  138. SMDiagnostic(SrcMgr, SMLoc(), "<unknown>", 0, -1, SourceMgr::DK_Error,
  139. "Attempting to expand an undeclared variable foo", "", {}));
  140. }
  141. // ${foo} is an undefined expansion and should error. When given a valid
  142. // location for the start of the buffer it should correctly point at the
  143. // expansion being performed.
  144. TEST(CodeExpander, UndefinedExpansionWithLoc) {
  145. std::string Result;
  146. raw_string_ostream OS(Result);
  147. CodeExpansions Expansions;
  148. Expansions.declare("bar", "expansion");
  149. RAIIDiagnosticChecker DiagChecker;
  150. StringRef In = bufferize("Padding ${foo}${bar}");
  151. CodeExpander(In, Expansions, SMLoc::getFromPointer(In.data()), false)
  152. .emit(OS);
  153. EXPECT_EQ(OS.str(), "Padding expansion");
  154. DiagChecker.expect(SMDiagnostic(
  155. SrcMgr, SMLoc::getFromPointer(In.data() + 8), "TestBuffer", 1, 8,
  156. SourceMgr::DK_Error, "Attempting to expand an undeclared variable foo",
  157. "Padding ${foo}${bar}", {}));
  158. }
  159. // ${bar is an unterminated expansion. Warn and implicitly terminate it.
  160. TEST(CodeExpander, UnterminatedExpansion) {
  161. std::string Result;
  162. raw_string_ostream OS(Result);
  163. CodeExpansions Expansions;
  164. Expansions.declare("bar", "expansion");
  165. RAIIDiagnosticChecker DiagChecker;
  166. StringRef In = bufferize(" ${bar");
  167. CodeExpander(In, Expansions, SMLoc::getFromPointer(In.data()), false)
  168. .emit(OS);
  169. EXPECT_EQ(OS.str(), " expansion");
  170. DiagChecker.expect(SMDiagnostic(SrcMgr, SMLoc::getFromPointer(In.data() + 1),
  171. "TestBuffer", 1, 1, SourceMgr::DK_Warning,
  172. "Unterminated expansion", " ${bar", {}));
  173. }