xref: /llvm-project/llvm/unittests/ADT/ScopedHashTableTest.cpp (revision c94ce0cca25229cd0e38560ad6e56a1a2f9a0c8b)
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