14aee81c4SRaphael Isemann //===-- ClangExpressionDeclMapTest.cpp ------------------------------------===//
24aee81c4SRaphael Isemann //
34aee81c4SRaphael Isemann // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44aee81c4SRaphael Isemann // See https://llvm.org/LICENSE.txt for license information.
54aee81c4SRaphael Isemann // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64aee81c4SRaphael Isemann //
74aee81c4SRaphael Isemann //===----------------------------------------------------------------------===//
84aee81c4SRaphael Isemann 
94aee81c4SRaphael Isemann #include "Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h"
108be30215SAlex Langford #include "Plugins/ExpressionParser/Clang/ClangUtil.h"
118be30215SAlex Langford #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
125dca0596SRaphael Isemann #include "TestingSupport/SubsystemRAII.h"
13aaa34bc0SRaphael Isemann #include "TestingSupport/Symbol/ClangTestUtils.h"
144aee81c4SRaphael Isemann #include "lldb/Host/FileSystem.h"
154aee81c4SRaphael Isemann #include "lldb/Host/HostInfo.h"
164aee81c4SRaphael Isemann #include "lldb/lldb-defines.h"
174aee81c4SRaphael Isemann #include "gtest/gtest.h"
184aee81c4SRaphael Isemann 
194aee81c4SRaphael Isemann using namespace lldb_private;
204aee81c4SRaphael Isemann using namespace lldb;
214aee81c4SRaphael Isemann 
22d8a31949SRaphael Isemann namespace {
23d8a31949SRaphael Isemann struct FakeClangExpressionDeclMap : public ClangExpressionDeclMap {
FakeClangExpressionDeclMap__anonf62ad2c90111::FakeClangExpressionDeclMap247c9ebdd3SAlex Langford   FakeClangExpressionDeclMap(const std::shared_ptr<ClangASTImporter> &importer)
25d8a31949SRaphael Isemann       : ClangExpressionDeclMap(false, nullptr, lldb::TargetSP(), importer,
26d8a31949SRaphael Isemann                                nullptr) {
276be76f49SRaphael Isemann     m_scratch_context = clang_utils::createAST();
28d8a31949SRaphael Isemann   }
296e3b0cc2SRaphael Isemann   std::unique_ptr<TypeSystemClang> m_scratch_context;
30d8a31949SRaphael Isemann   /// Adds a persistent decl that can be found by the ClangExpressionDeclMap
31d8a31949SRaphael Isemann   /// via GetPersistentDecl.
AddPersistentDeclForTest__anonf62ad2c90111::FakeClangExpressionDeclMap32d8a31949SRaphael Isemann   void AddPersistentDeclForTest(clang::NamedDecl *d) {
33d8a31949SRaphael Isemann     // The declaration needs to have '$' prefix in its name like every
34d8a31949SRaphael Isemann     // persistent declaration and must be inside the scratch AST context.
35d8a31949SRaphael Isemann     assert(d);
36d8a31949SRaphael Isemann     assert(d->getName().startswith("$"));
37f9f49d35SRaphael Isemann     assert(&d->getASTContext() == &m_scratch_context->getASTContext());
38d8a31949SRaphael Isemann     m_persistent_decls[d->getName()] = d;
39d8a31949SRaphael Isemann   }
40d8a31949SRaphael Isemann 
41d8a31949SRaphael Isemann protected:
42d8a31949SRaphael Isemann   // ClangExpressionDeclMap hooks.
43d8a31949SRaphael Isemann 
GetPersistentDecl__anonf62ad2c90111::FakeClangExpressionDeclMap44d8a31949SRaphael Isemann   clang::NamedDecl *GetPersistentDecl(ConstString name) override {
45d8a31949SRaphael Isemann     // ClangExpressionDeclMap wants to know if there is a persistent decl
46d8a31949SRaphael Isemann     // with the given name. Check the
47d8a31949SRaphael Isemann     return m_persistent_decls.lookup(name.GetStringRef());
48d8a31949SRaphael Isemann   }
49d8a31949SRaphael Isemann 
50d8a31949SRaphael Isemann private:
51d8a31949SRaphael Isemann   /// The persistent decls in this test with their names as keys.
52d8a31949SRaphael Isemann   llvm::DenseMap<llvm::StringRef, clang::NamedDecl *> m_persistent_decls;
53d8a31949SRaphael Isemann };
54d8a31949SRaphael Isemann } // namespace
55d8a31949SRaphael Isemann 
564aee81c4SRaphael Isemann namespace {
574aee81c4SRaphael Isemann struct ClangExpressionDeclMapTest : public testing::Test {
585dca0596SRaphael Isemann   SubsystemRAII<FileSystem, HostInfo> subsystems;
594aee81c4SRaphael Isemann 
60d8a31949SRaphael Isemann   /// The ClangASTImporter used during the test.
617c9ebdd3SAlex Langford   std::shared_ptr<ClangASTImporter> importer;
62d8a31949SRaphael Isemann   /// The ExpressionDeclMap for the current test case.
63d8a31949SRaphael Isemann   std::unique_ptr<FakeClangExpressionDeclMap> decl_map;
64d8a31949SRaphael Isemann 
65d8a31949SRaphael Isemann   /// The target AST that lookup results should be imported to.
666e3b0cc2SRaphael Isemann   std::unique_ptr<TypeSystemClang> target_ast;
67d8a31949SRaphael Isemann 
SetUp__anonf62ad2c90211::ClangExpressionDeclMapTest68d8a31949SRaphael Isemann   void SetUp() override {
69d8a31949SRaphael Isemann     importer = std::make_shared<ClangASTImporter>();
70d8a31949SRaphael Isemann     decl_map = std::make_unique<FakeClangExpressionDeclMap>(importer);
71aaa34bc0SRaphael Isemann     target_ast = clang_utils::createAST();
7249b206f9SRaphael Isemann     decl_map->InstallASTContext(*target_ast);
73d8a31949SRaphael Isemann   }
74d8a31949SRaphael Isemann 
TearDown__anonf62ad2c90211::ClangExpressionDeclMapTest75d8a31949SRaphael Isemann   void TearDown() override {
76d8a31949SRaphael Isemann     importer.reset();
77d8a31949SRaphael Isemann     decl_map.reset();
78d8a31949SRaphael Isemann     target_ast.reset();
794aee81c4SRaphael Isemann   }
804aee81c4SRaphael Isemann };
814aee81c4SRaphael Isemann } // namespace
824aee81c4SRaphael Isemann 
TEST_F(ClangExpressionDeclMapTest,TestUnknownIdentifierLookup)83d8a31949SRaphael Isemann TEST_F(ClangExpressionDeclMapTest, TestUnknownIdentifierLookup) {
84d8a31949SRaphael Isemann   // Tests looking up an identifier that can't be found anywhere.
854aee81c4SRaphael Isemann 
86d8a31949SRaphael Isemann   // Setup a NameSearchContext for 'foo'.
874aee81c4SRaphael Isemann   llvm::SmallVector<clang::NamedDecl *, 16> decls;
88aaa34bc0SRaphael Isemann   clang::DeclarationName name =
89aaa34bc0SRaphael Isemann       clang_utils::getDeclarationName(*target_ast, "foo");
90d8a31949SRaphael Isemann   const clang::DeclContext *dc = target_ast->GetTranslationUnitDecl();
91*defd0e24SRaphael Isemann   NameSearchContext search(*target_ast, decls, name, dc);
924aee81c4SRaphael Isemann 
93d8a31949SRaphael Isemann   decl_map->FindExternalVisibleDecls(search);
944aee81c4SRaphael Isemann 
95d8a31949SRaphael Isemann   // This shouldn't exist so we should get no lookups.
964aee81c4SRaphael Isemann   EXPECT_EQ(0U, decls.size());
974aee81c4SRaphael Isemann }
98d8a31949SRaphael Isemann 
TEST_F(ClangExpressionDeclMapTest,TestPersistentDeclLookup)99d8a31949SRaphael Isemann TEST_F(ClangExpressionDeclMapTest, TestPersistentDeclLookup) {
100d8a31949SRaphael Isemann   // Tests looking up a persistent decl from the scratch AST context.
101d8a31949SRaphael Isemann 
102d8a31949SRaphael Isemann   // Create a '$persistent_class' record and add it as a persistent variable
103d8a31949SRaphael Isemann   // to the scratch AST context.
104d8a31949SRaphael Isemann   llvm::StringRef decl_name = "$persistent_class";
105d8a31949SRaphael Isemann   CompilerType persistent_type =
106aaa34bc0SRaphael Isemann       clang_utils::createRecord(*decl_map->m_scratch_context, decl_name);
107d8a31949SRaphael Isemann   decl_map->AddPersistentDeclForTest(ClangUtil::GetAsTagDecl(persistent_type));
108d8a31949SRaphael Isemann 
109d8a31949SRaphael Isemann   // Setup a NameSearchContext for $persistent_class;
110d8a31949SRaphael Isemann   llvm::SmallVector<clang::NamedDecl *, 16> decls;
111aaa34bc0SRaphael Isemann   clang::DeclarationName name =
112aaa34bc0SRaphael Isemann       clang_utils::getDeclarationName(*target_ast, decl_name);
113d8a31949SRaphael Isemann   const clang::DeclContext *dc = target_ast->GetTranslationUnitDecl();
114*defd0e24SRaphael Isemann   NameSearchContext search(*target_ast, decls, name, dc);
115d8a31949SRaphael Isemann 
116d8a31949SRaphael Isemann   // Search and check that we found $persistent_class.
117d8a31949SRaphael Isemann   decl_map->FindExternalVisibleDecls(search);
118d8a31949SRaphael Isemann   EXPECT_EQ(1U, decls.size());
119d8a31949SRaphael Isemann   EXPECT_EQ(decl_name, decls.front()->getQualifiedNameAsString());
120d8a31949SRaphael Isemann   auto *record = llvm::cast<clang::RecordDecl>(decls.front());
121d8a31949SRaphael Isemann   // The class was minimally imported from the scratch AST context.
122d8a31949SRaphael Isemann   EXPECT_TRUE(record->hasExternalLexicalStorage());
123d8a31949SRaphael Isemann }
124