xref: /llvm-project/llvm/unittests/TableGen/CodeExpanderTest.cpp (revision fa3d789df15bd1f58fb8ba4ea3be909218cf7f03)
118350af1SDaniel Sanders //===- llvm/unittest/TableGen/CodeExpanderTest.cpp - Tests ----------------===//
218350af1SDaniel Sanders //
318350af1SDaniel Sanders // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
418350af1SDaniel Sanders // See https://llvm.org/LICENSE.txt for license information.
518350af1SDaniel Sanders // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
618350af1SDaniel Sanders //
718350af1SDaniel Sanders //===----------------------------------------------------------------------===//
818350af1SDaniel Sanders 
9*fa3d789dSPierre van Houtryve #include "Common/GlobalISel/CodeExpander.h"
10*fa3d789dSPierre van Houtryve #include "Common/GlobalISel/CodeExpansions.h"
1118350af1SDaniel Sanders 
1218350af1SDaniel Sanders #include "llvm/Support/raw_ostream.h"
1318350af1SDaniel Sanders #include "llvm/TableGen/Error.h"
1418350af1SDaniel Sanders #include "gtest/gtest.h"
1518350af1SDaniel Sanders 
1618350af1SDaniel Sanders using namespace llvm;
1718350af1SDaniel Sanders 
bufferize(StringRef Str)1818350af1SDaniel Sanders static StringRef bufferize(StringRef Str) {
1918350af1SDaniel Sanders   std::unique_ptr<MemoryBuffer> Buffer =
2018350af1SDaniel Sanders       MemoryBuffer::getMemBufferCopy(Str, "TestBuffer");
2118350af1SDaniel Sanders   StringRef StrBufferRef = Buffer->getBuffer();
2218350af1SDaniel Sanders   SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc());
2318350af1SDaniel Sanders   return StrBufferRef;
2418350af1SDaniel Sanders }
2518350af1SDaniel Sanders 
2618350af1SDaniel Sanders class RAIIDiagnosticChecker {
2718350af1SDaniel Sanders   std::string EmittedDiags;
2818350af1SDaniel Sanders   raw_string_ostream OS;
2918350af1SDaniel Sanders   std::vector<SMDiagnostic> Expected;
3018350af1SDaniel Sanders   std::vector<SMDiagnostic> Received;
3118350af1SDaniel Sanders 
3218350af1SDaniel Sanders public:
RAIIDiagnosticChecker()3318350af1SDaniel Sanders   RAIIDiagnosticChecker() : OS(EmittedDiags) {
3418350af1SDaniel Sanders     SrcMgr.setDiagHandler(handler, this);
3518350af1SDaniel Sanders   }
~RAIIDiagnosticChecker()3618350af1SDaniel Sanders   ~RAIIDiagnosticChecker() {
3718350af1SDaniel Sanders     SrcMgr.setDiagHandler(nullptr);
3818350af1SDaniel Sanders     EXPECT_EQ(Received.size(), Expected.size());
3918350af1SDaniel Sanders     for (unsigned i = 0; i < Received.size() && i < Expected.size(); ++i) {
4018350af1SDaniel Sanders       EXPECT_EQ(Received[i].getLoc(), Expected[i].getLoc());
4118350af1SDaniel Sanders       EXPECT_EQ(Received[i].getFilename(), Expected[i].getFilename());
4218350af1SDaniel Sanders       EXPECT_EQ(Received[i].getKind(), Expected[i].getKind());
4318350af1SDaniel Sanders       EXPECT_EQ(Received[i].getLineNo(), Expected[i].getLineNo());
4418350af1SDaniel Sanders       EXPECT_EQ(Received[i].getColumnNo(), Expected[i].getColumnNo());
4518350af1SDaniel Sanders       EXPECT_EQ(Received[i].getMessage(), Expected[i].getMessage());
4618350af1SDaniel Sanders       EXPECT_EQ(Received[i].getLineContents(), Expected[i].getLineContents());
4718350af1SDaniel Sanders       EXPECT_EQ(Received[i].getRanges(), Expected[i].getRanges());
4818350af1SDaniel Sanders     }
4918350af1SDaniel Sanders 
5018350af1SDaniel Sanders     if (testing::Test::HasFailure())
5118350af1SDaniel Sanders       errs() << "Emitted diagnostic:\n" << OS.str();
5218350af1SDaniel Sanders   }
5318350af1SDaniel Sanders 
expect(SMDiagnostic D)5418350af1SDaniel Sanders   void expect(SMDiagnostic D) { Expected.push_back(D); }
5518350af1SDaniel Sanders 
diag(const SMDiagnostic & D)5618350af1SDaniel Sanders   void diag(const SMDiagnostic &D) {
5718350af1SDaniel Sanders     Received.push_back(D);
5818350af1SDaniel Sanders   }
5918350af1SDaniel Sanders 
handler(const SMDiagnostic & D,void * Context)6018350af1SDaniel Sanders   static void handler(const SMDiagnostic &D, void *Context) {
6118350af1SDaniel Sanders     RAIIDiagnosticChecker *Self = static_cast<RAIIDiagnosticChecker *>(Context);
6218350af1SDaniel Sanders     Self->diag(D);
6318350af1SDaniel Sanders     SrcMgr.setDiagHandler(nullptr);
6418350af1SDaniel Sanders     SrcMgr.PrintMessage(Self->OS, D);
6518350af1SDaniel Sanders     SrcMgr.setDiagHandler(handler, Context);
6618350af1SDaniel Sanders   };
6718350af1SDaniel Sanders };
6818350af1SDaniel Sanders 
TEST(CodeExpander,NoExpansions)6918350af1SDaniel Sanders TEST(CodeExpander, NoExpansions) {
7018350af1SDaniel Sanders   std::string Result;
7118350af1SDaniel Sanders   raw_string_ostream OS(Result);
7218350af1SDaniel Sanders   CodeExpansions Expansions;
7318350af1SDaniel Sanders 
7418350af1SDaniel Sanders   RAIIDiagnosticChecker DiagChecker;
7518350af1SDaniel Sanders   CodeExpander("No expansions", Expansions, SMLoc(), false).emit(OS);
7618350af1SDaniel Sanders   EXPECT_EQ(OS.str(), "No expansions");
7718350af1SDaniel Sanders }
7818350af1SDaniel Sanders 
7918350af1SDaniel Sanders // Indentation is applied to all lines except the first
TEST(CodeExpander,Indentation)8018350af1SDaniel Sanders TEST(CodeExpander, Indentation) {
8118350af1SDaniel Sanders   std::string Result;
8218350af1SDaniel Sanders   raw_string_ostream OS(Result);
8318350af1SDaniel Sanders   CodeExpansions Expansions;
8418350af1SDaniel Sanders 
8518350af1SDaniel Sanders   RAIIDiagnosticChecker DiagChecker;
8618350af1SDaniel Sanders   CodeExpander("No expansions\nsecond line\nthird line", Expansions, SMLoc(),
8718350af1SDaniel Sanders                false, "  ")
8818350af1SDaniel Sanders       .emit(OS);
8918350af1SDaniel Sanders   EXPECT_EQ(OS.str(), "No expansions\n  second line\n  third line");
9018350af1SDaniel Sanders }
9118350af1SDaniel Sanders 
9218350af1SDaniel Sanders // \ is an escape character that removes special meanings from the next
9318350af1SDaniel Sanders // character.
TEST(CodeExpander,Escape)9418350af1SDaniel Sanders TEST(CodeExpander, Escape) {
9518350af1SDaniel Sanders   std::string Result;
9618350af1SDaniel Sanders   raw_string_ostream OS(Result);
9718350af1SDaniel Sanders   CodeExpansions Expansions;
9818350af1SDaniel Sanders 
9918350af1SDaniel Sanders   RAIIDiagnosticChecker DiagChecker;
10018350af1SDaniel Sanders   CodeExpander("\\\\\\a\\$", Expansions, SMLoc(), false).emit(OS);
10118350af1SDaniel Sanders   EXPECT_EQ(OS.str(), "\\a$");
10218350af1SDaniel Sanders }
10318350af1SDaniel Sanders 
10418350af1SDaniel Sanders // $foo is not an expansion. It should warn though.
TEST(CodeExpander,NotAnExpansion)10518350af1SDaniel Sanders TEST(CodeExpander, NotAnExpansion) {
10618350af1SDaniel Sanders   std::string Result;
10718350af1SDaniel Sanders   raw_string_ostream OS(Result);
10818350af1SDaniel Sanders   CodeExpansions Expansions;
10918350af1SDaniel Sanders 
11018350af1SDaniel Sanders   RAIIDiagnosticChecker DiagChecker;
11118350af1SDaniel Sanders   StringRef In = bufferize(" $foo");
11218350af1SDaniel Sanders   CodeExpander(" $foo", Expansions, SMLoc::getFromPointer(In.data()), false)
11318350af1SDaniel Sanders       .emit(OS);
11418350af1SDaniel Sanders   EXPECT_EQ(OS.str(), " $foo");
11518350af1SDaniel Sanders   DiagChecker.expect(SMDiagnostic(
116b23e84ffSPaul C. Anagnostopoulos       SrcMgr, SMLoc::getFromPointer(In.data()), "TestBuffer", 1, 0,
117b23e84ffSPaul C. Anagnostopoulos       SourceMgr::DK_Warning, "Assuming missing escape character: \\$", " $foo", {}));
11818350af1SDaniel Sanders }
11918350af1SDaniel Sanders 
12018350af1SDaniel Sanders // \$foo is not an expansion but shouldn't warn as it's using the escape.
TEST(CodeExpander,EscapedNotAnExpansion)12118350af1SDaniel Sanders TEST(CodeExpander, EscapedNotAnExpansion) {
12218350af1SDaniel Sanders   std::string Result;
12318350af1SDaniel Sanders   raw_string_ostream OS(Result);
12418350af1SDaniel Sanders   CodeExpansions Expansions;
12518350af1SDaniel Sanders 
12618350af1SDaniel Sanders   RAIIDiagnosticChecker DiagChecker;
12718350af1SDaniel Sanders   CodeExpander("\\$foo", Expansions, SMLoc(), false).emit(OS);
12818350af1SDaniel Sanders   EXPECT_EQ(OS.str(), "$foo");
12918350af1SDaniel Sanders }
13018350af1SDaniel Sanders 
13118350af1SDaniel Sanders // \${foo is not an expansion but shouldn't warn as it's using the escape.
TEST(CodeExpander,EscapedUnterminatedExpansion)13218350af1SDaniel Sanders TEST(CodeExpander, EscapedUnterminatedExpansion) {
13318350af1SDaniel Sanders   std::string Result;
13418350af1SDaniel Sanders   raw_string_ostream OS(Result);
13518350af1SDaniel Sanders   CodeExpansions Expansions;
13618350af1SDaniel Sanders 
13718350af1SDaniel Sanders   RAIIDiagnosticChecker DiagChecker;
13818350af1SDaniel Sanders   CodeExpander("\\${foo", Expansions, SMLoc(), false).emit(OS);
13918350af1SDaniel Sanders   EXPECT_EQ(OS.str(), "${foo");
14018350af1SDaniel Sanders }
14118350af1SDaniel Sanders 
14218350af1SDaniel Sanders // \${foo is not an expansion but shouldn't warn as it's using the escape.
TEST(CodeExpander,EscapedExpansion)14318350af1SDaniel Sanders TEST(CodeExpander, EscapedExpansion) {
14418350af1SDaniel Sanders   std::string Result;
14518350af1SDaniel Sanders   raw_string_ostream OS(Result);
14618350af1SDaniel Sanders   CodeExpansions Expansions;
14718350af1SDaniel Sanders 
14818350af1SDaniel Sanders   RAIIDiagnosticChecker DiagChecker;
14918350af1SDaniel Sanders   CodeExpander("\\${foo}", Expansions, SMLoc(), false).emit(OS);
15018350af1SDaniel Sanders   EXPECT_EQ(OS.str(), "${foo}");
15118350af1SDaniel Sanders }
15218350af1SDaniel Sanders 
15318350af1SDaniel Sanders // ${foo} is an undefined expansion and should error.
TEST(CodeExpander,UndefinedExpansion)15418350af1SDaniel Sanders TEST(CodeExpander, UndefinedExpansion) {
15518350af1SDaniel Sanders   std::string Result;
15618350af1SDaniel Sanders   raw_string_ostream OS(Result);
15718350af1SDaniel Sanders   CodeExpansions Expansions;
15818350af1SDaniel Sanders   Expansions.declare("bar", "expansion");
15918350af1SDaniel Sanders 
16018350af1SDaniel Sanders   RAIIDiagnosticChecker DiagChecker;
16118350af1SDaniel Sanders   CodeExpander("${foo}${bar}", Expansions, SMLoc(), false).emit(OS);
16218350af1SDaniel Sanders   EXPECT_EQ(OS.str(), "expansion");
16318350af1SDaniel Sanders   DiagChecker.expect(
16418350af1SDaniel Sanders       SMDiagnostic(SrcMgr, SMLoc(), "<unknown>", 0, -1, SourceMgr::DK_Error,
165b23e84ffSPaul C. Anagnostopoulos                    "Attempt to expand an undeclared variable 'foo'", "", {}));
16618350af1SDaniel Sanders }
16718350af1SDaniel Sanders 
16818350af1SDaniel Sanders // ${bar is an unterminated expansion. Warn and implicitly terminate it.
TEST(CodeExpander,UnterminatedExpansion)16918350af1SDaniel Sanders TEST(CodeExpander, UnterminatedExpansion) {
17018350af1SDaniel Sanders   std::string Result;
17118350af1SDaniel Sanders   raw_string_ostream OS(Result);
17218350af1SDaniel Sanders   CodeExpansions Expansions;
17318350af1SDaniel Sanders   Expansions.declare("bar", "expansion");
17418350af1SDaniel Sanders 
17518350af1SDaniel Sanders   RAIIDiagnosticChecker DiagChecker;
17618350af1SDaniel Sanders   StringRef In = bufferize(" ${bar");
17718350af1SDaniel Sanders   CodeExpander(In, Expansions, SMLoc::getFromPointer(In.data()), false)
17818350af1SDaniel Sanders       .emit(OS);
17918350af1SDaniel Sanders   EXPECT_EQ(OS.str(), " expansion");
180b23e84ffSPaul C. Anagnostopoulos   DiagChecker.expect(SMDiagnostic(SrcMgr, SMLoc::getFromPointer(In.data()),
181b23e84ffSPaul C. Anagnostopoulos                                   "TestBuffer", 1, 0, SourceMgr::DK_Warning,
182b23e84ffSPaul C. Anagnostopoulos                                   "Unterminated expansion '${bar'", " ${bar", {}));
18318350af1SDaniel Sanders }
184