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