1 //===- ScopedHashTableTest.cpp - ScopedHashTable unit 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 9 #include "llvm/ADT/ScopedHashTable.h" 10 #include "llvm/ADT/StringRef.h" 11 #include "gtest/gtest.h" 12 #include <memory> 13 #include <stack> 14 15 using ::llvm::ScopedHashTable; 16 using ::llvm::ScopedHashTableScope; 17 using ::llvm::StringLiteral; 18 using ::llvm::StringRef; 19 20 using ::testing::Test; 21 22 class ScopedHashTableTest : public Test { 23 protected: 24 ScopedHashTableTest() { symbolTable.insert(kGlobalName, kGlobalValue); } 25 26 ScopedHashTable<StringRef, StringRef> symbolTable{}; 27 ScopedHashTableScope<StringRef, StringRef> globalScope{symbolTable}; 28 29 static constexpr StringLiteral kGlobalName = "global"; 30 static constexpr StringLiteral kGlobalValue = "gvalue"; 31 static constexpr StringLiteral kLocalName = "local"; 32 static constexpr StringLiteral kLocalValue = "lvalue"; 33 static constexpr StringLiteral kLocalValue2 = "lvalue2"; 34 }; 35 36 TEST_F(ScopedHashTableTest, AccessWithNoActiveScope) { 37 EXPECT_EQ(symbolTable.count(kGlobalName), 1U); 38 } 39 40 TEST_F(ScopedHashTableTest, AccessWithAScope) { 41 [[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> varScope( 42 symbolTable); 43 EXPECT_EQ(symbolTable.count(kGlobalName), 1U); 44 } 45 46 TEST_F(ScopedHashTableTest, InsertInScope) { 47 [[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> varScope( 48 symbolTable); 49 symbolTable.insert(kLocalName, kLocalValue); 50 EXPECT_EQ(symbolTable.count(kLocalName), 1U); 51 } 52 53 TEST_F(ScopedHashTableTest, InsertInLinearSortedScope) { 54 [[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> varScope( 55 symbolTable); 56 [[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> varScope2( 57 symbolTable); 58 [[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> varScope3( 59 symbolTable); 60 symbolTable.insert(kLocalName, kLocalValue); 61 EXPECT_EQ(symbolTable.count(kLocalName), 1U); 62 } 63 64 TEST_F(ScopedHashTableTest, InsertInOutedScope) { 65 { 66 [[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> varScope( 67 symbolTable); 68 symbolTable.insert(kLocalName, kLocalValue); 69 } 70 EXPECT_EQ(symbolTable.count(kLocalName), 0U); 71 } 72 73 TEST_F(ScopedHashTableTest, OverrideInScope) { 74 [[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> funScope( 75 symbolTable); 76 symbolTable.insert(kLocalName, kLocalValue); 77 { 78 [[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> varScope( 79 symbolTable); 80 symbolTable.insert(kLocalName, kLocalValue2); 81 EXPECT_EQ(symbolTable.lookup(kLocalName), kLocalValue2); 82 } 83 EXPECT_EQ(symbolTable.lookup(kLocalName), kLocalValue); 84 } 85 86 TEST_F(ScopedHashTableTest, GetCurScope) { 87 EXPECT_EQ(symbolTable.getCurScope(), &globalScope); 88 { 89 ScopedHashTableScope<StringRef, StringRef> funScope(symbolTable); 90 ScopedHashTableScope<StringRef, StringRef> funScope2(symbolTable); 91 EXPECT_EQ(symbolTable.getCurScope(), &funScope2); 92 { 93 ScopedHashTableScope<StringRef, StringRef> blockScope(symbolTable); 94 EXPECT_EQ(symbolTable.getCurScope(), &blockScope); 95 } 96 EXPECT_EQ(symbolTable.getCurScope(), &funScope2); 97 } 98 EXPECT_EQ(symbolTable.getCurScope(), &globalScope); 99 } 100 101 TEST_F(ScopedHashTableTest, PopScope) { 102 using SymbolTableScopeTy = ScopedHashTable<StringRef, StringRef>::ScopeTy; 103 104 std::stack<StringRef> ExpectedValues; 105 std::stack<std::unique_ptr<SymbolTableScopeTy>> Scopes; 106 107 Scopes.emplace(std::make_unique<SymbolTableScopeTy>(symbolTable)); 108 ExpectedValues.emplace(kLocalValue); 109 symbolTable.insert(kGlobalName, kLocalValue); 110 111 Scopes.emplace(std::make_unique<SymbolTableScopeTy>(symbolTable)); 112 ExpectedValues.emplace(kLocalValue2); 113 symbolTable.insert(kGlobalName, kLocalValue2); 114 115 while (symbolTable.getCurScope() != &globalScope) { 116 EXPECT_EQ(symbolTable.getCurScope(), Scopes.top().get()); 117 EXPECT_EQ(symbolTable.lookup(kGlobalName), ExpectedValues.top()); 118 ExpectedValues.pop(); 119 Scopes.pop(); // destructs the SymbolTableScopeTy instance implicitly 120 // calling Scopes.top()->~SymbolTableScopeTy(); 121 EXPECT_NE(symbolTable.getCurScope(), nullptr); 122 } 123 ASSERT_TRUE(ExpectedValues.empty()); 124 ASSERT_TRUE(Scopes.empty()); 125 EXPECT_EQ(symbolTable.lookup(kGlobalName), kGlobalValue); 126 } 127 128 TEST_F(ScopedHashTableTest, DISABLED_PopScopeOnStack) { 129 using SymbolTableScopeTy = ScopedHashTable<StringRef, StringRef>::ScopeTy; 130 SymbolTableScopeTy funScope(symbolTable); 131 symbolTable.insert(kGlobalName, kLocalValue); 132 SymbolTableScopeTy funScope2(symbolTable); 133 symbolTable.insert(kGlobalName, kLocalValue2); 134 135 std::stack<StringRef> expectedValues{{kLocalValue, kLocalValue2}}; 136 std::stack<SymbolTableScopeTy *> expectedScopes{{&funScope, &funScope2}}; 137 138 while (symbolTable.getCurScope() != &globalScope) { 139 EXPECT_EQ(symbolTable.getCurScope(), expectedScopes.top()); 140 expectedScopes.pop(); 141 EXPECT_EQ(symbolTable.lookup(kGlobalName), expectedValues.top()); 142 expectedValues.pop(); 143 symbolTable.getCurScope()->~SymbolTableScopeTy(); 144 EXPECT_NE(symbolTable.getCurScope(), nullptr); 145 } 146 147 // We have imbalanced scopes here: 148 // Assertion `HT.CurScope == this && "Scope imbalance!"' failed 149 // HT.CurScope is a pointer to the `globalScope` while 150 // `SymbolTableScopeTy.this` is still a pointer to `funScope2`. 151 // There is no way to write an assert on an assert in googletest so that we 152 // mark the test case as DISABLED. 153 } 154